diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ dist coverage .env +.venv .next .nuxt .output diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -25,8 +25,11 @@ "examples:check": "sh ./scripts/examples-check.sh", "examples:generate": "sh ./scripts/examples-generate.sh", "format": "oxfmt .", - "lint:fix": "oxfmt . && eslint . --fix", + "format:next": "oxfmt . && uv run ruff format packages/openapi-python/src/ts-python/__snapshots__", "lint": "oxfmt --check . && eslint .", + "lint:next": "oxfmt --check . && eslint . && uv run ruff check packages/openapi-python/src/ts-python/__snapshots__", + "lint:fix": "oxfmt . && eslint . --fix", + "lint:fix:next": "oxfmt . && eslint . --fix && uv run ruff check --fix packages/openapi-python/src/ts-python/__snapshots__", "prepare": "husky", "test:changelog": "vitest run __tests__/*.test.ts", "test:changelog:watch": "vitest watch __tests__/*.test.ts", @@ -39,6 +42,7 @@ "tw": "turbo run test:watch --filter", "tu": "turbo run test:update --filter", "tb": "turbo run build --filter", + "ty": "turbo run typecheck --filter", "dev:ts": "cd dev && tsx watch --clear-screen=false ../packages/openapi-ts/src/run.ts", "dev:py": "cd dev && tsx watch --clear-screen=false ../packages/openapi-python/src/run.ts" }, diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "hey-api-dev" +version = "0.0.0" +requires-python = ">=3.10" + +[dependency-groups] +dev = ["mypy>=1.15", "ruff>=0.11"] + +[tool.mypy] +python_version = "3.10" +strict = false +warn_return_any = true +warn_unused_configs = true + +[tool.ruff] +line-length = 120 +target-version = "py310" + +[tool.ruff.format] +exclude = ["**/__snapshots__/**"] + +[tool.ruff.lint] +select = ["E", "F", "W", "I"] diff --git a/turbo.json b/turbo.json --- a/turbo.json +++ b/turbo.json @@ -41,7 +41,14 @@ }, "typecheck": { "dependsOn": ["^build"], - "inputs": ["src/**", "test/**", "*.config.*", "package.json", "tsconfig.json"] + "inputs": [ + "src/**", + "test/**", + "*.config.*", + "package.json", + "tsconfig.json", + "pyproject.toml" + ] } } } diff --git a/uv.lock b/uv.lock new file mode 100644 --- /dev/null +++ b/uv.lock @@ -0,0 +1,248 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" + +[[package]] +name = "hey-api-dev" +version = "0.0.0" +source = { virtual = "." } + +[package.dev-dependencies] +dev = [ + { name = "mypy" }, + { name = "ruff" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "mypy", specifier = ">=1.15" }, + { name = "ruff", specifier = ">=0.11" }, +] + +[[package]] +name = "librt" +version = "0.7.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/24/5f3646ff414285e0f7708fa4e946b9bf538345a41d1c375c439467721a5e/librt-0.7.8.tar.gz", hash = "sha256:1a4ede613941d9c3470b0368be851df6bb78ab218635512d0370b27a277a0862", size = 148323, upload-time = "2026-01-14T12:56:16.876Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/13/57b06758a13550c5f09563893b004f98e9537ee6ec67b7df85c3571c8832/librt-0.7.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b45306a1fc5f53c9330fbee134d8b3227fe5da2ab09813b892790400aa49352d", size = 56521, upload-time = "2026-01-14T12:54:40.066Z" }, + { url = "https://files.pythonhosted.org/packages/c2/24/bbea34d1452a10612fb45ac8356f95351ba40c2517e429602160a49d1fd0/librt-0.7.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:864c4b7083eeee250ed55135d2127b260d7eb4b5e953a9e5df09c852e327961b", size = 58456, upload-time = "2026-01-14T12:54:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/04/72/a168808f92253ec3a810beb1eceebc465701197dbc7e865a1c9ceb3c22c7/librt-0.7.8-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6938cc2de153bc927ed8d71c7d2f2ae01b4e96359126c602721340eb7ce1a92d", size = 164392, upload-time = "2026-01-14T12:54:42.843Z" }, + { url = "https://files.pythonhosted.org/packages/14/5c/4c0d406f1b02735c2e7af8ff1ff03a6577b1369b91aa934a9fa2cc42c7ce/librt-0.7.8-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:66daa6ac5de4288a5bbfbe55b4caa7bf0cd26b3269c7a476ffe8ce45f837f87d", size = 172959, upload-time = "2026-01-14T12:54:44.602Z" }, + { url = "https://files.pythonhosted.org/packages/82/5f/3e85351c523f73ad8d938989e9a58c7f59fb9c17f761b9981b43f0025ce7/librt-0.7.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4864045f49dc9c974dadb942ac56a74cd0479a2aafa51ce272c490a82322ea3c", size = 186717, upload-time = "2026-01-14T12:54:45.986Z" }, + { url = "https://files.pythonhosted.org/packages/08/f8/18bfe092e402d00fe00d33aa1e01dda1bd583ca100b393b4373847eade6d/librt-0.7.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a36515b1328dc5b3ffce79fe204985ca8572525452eacabee2166f44bb387b2c", size = 184585, upload-time = "2026-01-14T12:54:47.139Z" }, + { url = "https://files.pythonhosted.org/packages/4e/fc/f43972ff56fd790a9fa55028a52ccea1875100edbb856b705bd393b601e3/librt-0.7.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b7e7f140c5169798f90b80d6e607ed2ba5059784968a004107c88ad61fb3641d", size = 180497, upload-time = "2026-01-14T12:54:48.946Z" }, + { url = "https://files.pythonhosted.org/packages/e1/3a/25e36030315a410d3ad0b7d0f19f5f188e88d1613d7d3fd8150523ea1093/librt-0.7.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ff71447cb778a4f772ddc4ce360e6ba9c95527ed84a52096bd1bbf9fee2ec7c0", size = 200052, upload-time = "2026-01-14T12:54:50.382Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b8/f3a5a1931ae2a6ad92bf6893b9ef44325b88641d58723529e2c2935e8abe/librt-0.7.8-cp310-cp310-win32.whl", hash = "sha256:047164e5f68b7a8ebdf9fae91a3c2161d3192418aadd61ddd3a86a56cbe3dc85", size = 43477, upload-time = "2026-01-14T12:54:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/fe/91/c4202779366bc19f871b4ad25db10fcfa1e313c7893feb942f32668e8597/librt-0.7.8-cp310-cp310-win_amd64.whl", hash = "sha256:d6f254d096d84156a46a84861183c183d30734e52383602443292644d895047c", size = 49806, upload-time = "2026-01-14T12:54:53.149Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a3/87ea9c1049f2c781177496ebee29430e4631f439b8553a4969c88747d5d8/librt-0.7.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ff3e9c11aa260c31493d4b3197d1e28dd07768594a4f92bec4506849d736248f", size = 56507, upload-time = "2026-01-14T12:54:54.156Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4a/23bcef149f37f771ad30203d561fcfd45b02bc54947b91f7a9ac34815747/librt-0.7.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ddb52499d0b3ed4aa88746aaf6f36a08314677d5c346234c3987ddc506404eac", size = 58455, upload-time = "2026-01-14T12:54:55.978Z" }, + { url = "https://files.pythonhosted.org/packages/22/6e/46eb9b85c1b9761e0f42b6e6311e1cc544843ac897457062b9d5d0b21df4/librt-0.7.8-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e9c0afebbe6ce177ae8edba0c7c4d626f2a0fc12c33bb993d163817c41a7a05c", size = 164956, upload-time = "2026-01-14T12:54:57.311Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3f/aa7c7f6829fb83989feb7ba9aa11c662b34b4bd4bd5b262f2876ba3db58d/librt-0.7.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:631599598e2c76ded400c0a8722dec09217c89ff64dc54b060f598ed68e7d2a8", size = 174364, upload-time = "2026-01-14T12:54:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/3f/2d/d57d154b40b11f2cb851c4df0d4c4456bacd9b1ccc4ecb593ddec56c1a8b/librt-0.7.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c1ba843ae20db09b9d5c80475376168feb2640ce91cd9906414f23cc267a1ff", size = 188034, upload-time = "2026-01-14T12:55:00.141Z" }, + { url = "https://files.pythonhosted.org/packages/59/f9/36c4dad00925c16cd69d744b87f7001792691857d3b79187e7a673e812fb/librt-0.7.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b5b007bb22ea4b255d3ee39dfd06d12534de2fcc3438567d9f48cdaf67ae1ae3", size = 186295, upload-time = "2026-01-14T12:55:01.303Z" }, + { url = "https://files.pythonhosted.org/packages/23/9b/8a9889d3df5efb67695a67785028ccd58e661c3018237b73ad081691d0cb/librt-0.7.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dbd79caaf77a3f590cbe32dc2447f718772d6eea59656a7dcb9311161b10fa75", size = 181470, upload-time = "2026-01-14T12:55:02.492Z" }, + { url = "https://files.pythonhosted.org/packages/43/64/54d6ef11afca01fef8af78c230726a9394759f2addfbf7afc5e3cc032a45/librt-0.7.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:87808a8d1e0bd62a01cafc41f0fd6818b5a5d0ca0d8a55326a81643cdda8f873", size = 201713, upload-time = "2026-01-14T12:55:03.919Z" }, + { url = "https://files.pythonhosted.org/packages/2d/29/73e7ed2991330b28919387656f54109139b49e19cd72902f466bd44415fd/librt-0.7.8-cp311-cp311-win32.whl", hash = "sha256:31724b93baa91512bd0a376e7cf0b59d8b631ee17923b1218a65456fa9bda2e7", size = 43803, upload-time = "2026-01-14T12:55:04.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/de/66766ff48ed02b4d78deea30392ae200bcbd99ae61ba2418b49fd50a4831/librt-0.7.8-cp311-cp311-win_amd64.whl", hash = "sha256:978e8b5f13e52cf23a9e80f3286d7546baa70bc4ef35b51d97a709d0b28e537c", size = 50080, upload-time = "2026-01-14T12:55:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/6f/e3/33450438ff3a8c581d4ed7f798a70b07c3206d298cf0b87d3806e72e3ed8/librt-0.7.8-cp311-cp311-win_arm64.whl", hash = "sha256:20e3946863d872f7cabf7f77c6c9d370b8b3d74333d3a32471c50d3a86c0a232", size = 43383, upload-time = "2026-01-14T12:55:07.49Z" }, + { url = "https://files.pythonhosted.org/packages/56/04/79d8fcb43cae376c7adbab7b2b9f65e48432c9eced62ac96703bcc16e09b/librt-0.7.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b6943885b2d49c48d0cff23b16be830ba46b0152d98f62de49e735c6e655a63", size = 57472, upload-time = "2026-01-14T12:55:08.528Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ba/60b96e93043d3d659da91752689023a73981336446ae82078cddf706249e/librt-0.7.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46ef1f4b9b6cc364b11eea0ecc0897314447a66029ee1e55859acb3dd8757c93", size = 58986, upload-time = "2026-01-14T12:55:09.466Z" }, + { url = "https://files.pythonhosted.org/packages/7c/26/5215e4cdcc26e7be7eee21955a7e13cbf1f6d7d7311461a6014544596fac/librt-0.7.8-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:907ad09cfab21e3c86e8f1f87858f7049d1097f77196959c033612f532b4e592", size = 168422, upload-time = "2026-01-14T12:55:10.499Z" }, + { url = "https://files.pythonhosted.org/packages/0f/84/e8d1bc86fa0159bfc24f3d798d92cafd3897e84c7fea7fe61b3220915d76/librt-0.7.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2991b6c3775383752b3ca0204842743256f3ad3deeb1d0adc227d56b78a9a850", size = 177478, upload-time = "2026-01-14T12:55:11.577Z" }, + { url = "https://files.pythonhosted.org/packages/57/11/d0268c4b94717a18aa91df1100e767b010f87b7ae444dafaa5a2d80f33a6/librt-0.7.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03679b9856932b8c8f674e87aa3c55ea11c9274301f76ae8dc4d281bda55cf62", size = 192439, upload-time = "2026-01-14T12:55:12.7Z" }, + { url = "https://files.pythonhosted.org/packages/8d/56/1e8e833b95fe684f80f8894ae4d8b7d36acc9203e60478fcae599120a975/librt-0.7.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3968762fec1b2ad34ce57458b6de25dbb4142713e9ca6279a0d352fa4e9f452b", size = 191483, upload-time = "2026-01-14T12:55:13.838Z" }, + { url = "https://files.pythonhosted.org/packages/17/48/f11cf28a2cb6c31f282009e2208312aa84a5ee2732859f7856ee306176d5/librt-0.7.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bb7a7807523a31f03061288cc4ffc065d684c39db7644c676b47d89553c0d714", size = 185376, upload-time = "2026-01-14T12:55:15.017Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6a/d7c116c6da561b9155b184354a60a3d5cdbf08fc7f3678d09c95679d13d9/librt-0.7.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad64a14b1e56e702e19b24aae108f18ad1bf7777f3af5fcd39f87d0c5a814449", size = 206234, upload-time = "2026-01-14T12:55:16.571Z" }, + { url = "https://files.pythonhosted.org/packages/61/de/1975200bb0285fc921c5981d9978ce6ce11ae6d797df815add94a5a848a3/librt-0.7.8-cp312-cp312-win32.whl", hash = "sha256:0241a6ed65e6666236ea78203a73d800dbed896cf12ae25d026d75dc1fcd1dac", size = 44057, upload-time = "2026-01-14T12:55:18.077Z" }, + { url = "https://files.pythonhosted.org/packages/8e/cd/724f2d0b3461426730d4877754b65d39f06a41ac9d0a92d5c6840f72b9ae/librt-0.7.8-cp312-cp312-win_amd64.whl", hash = "sha256:6db5faf064b5bab9675c32a873436b31e01d66ca6984c6f7f92621656033a708", size = 50293, upload-time = "2026-01-14T12:55:19.179Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cf/7e899acd9ee5727ad8160fdcc9994954e79fab371c66535c60e13b968ffc/librt-0.7.8-cp312-cp312-win_arm64.whl", hash = "sha256:57175aa93f804d2c08d2edb7213e09276bd49097611aefc37e3fa38d1fb99ad0", size = 43574, upload-time = "2026-01-14T12:55:20.185Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fe/b1f9de2829cf7fc7649c1dcd202cfd873837c5cc2fc9e526b0e7f716c3d2/librt-0.7.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4c3995abbbb60b3c129490fa985dfe6cac11d88fc3c36eeb4fb1449efbbb04fc", size = 57500, upload-time = "2026-01-14T12:55:21.219Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d4/4a60fbe2e53b825f5d9a77325071d61cd8af8506255067bf0c8527530745/librt-0.7.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44e0c2cbc9bebd074cf2cdbe472ca185e824be4e74b1c63a8e934cea674bebf2", size = 59019, upload-time = "2026-01-14T12:55:22.256Z" }, + { url = "https://files.pythonhosted.org/packages/6a/37/61ff80341ba5159afa524445f2d984c30e2821f31f7c73cf166dcafa5564/librt-0.7.8-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d2f1e492cae964b3463a03dc77a7fe8742f7855d7258c7643f0ee32b6651dd3", size = 169015, upload-time = "2026-01-14T12:55:23.24Z" }, + { url = "https://files.pythonhosted.org/packages/1c/86/13d4f2d6a93f181ebf2fc953868826653ede494559da8268023fe567fca3/librt-0.7.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:451e7ffcef8f785831fdb791bd69211f47e95dc4c6ddff68e589058806f044c6", size = 178161, upload-time = "2026-01-14T12:55:24.826Z" }, + { url = "https://files.pythonhosted.org/packages/88/26/e24ef01305954fc4d771f1f09f3dd682f9eb610e1bec188ffb719374d26e/librt-0.7.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3469e1af9f1380e093ae06bedcbdd11e407ac0b303a56bbe9afb1d6824d4982d", size = 193015, upload-time = "2026-01-14T12:55:26.04Z" }, + { url = "https://files.pythonhosted.org/packages/88/a0/92b6bd060e720d7a31ed474d046a69bd55334ec05e9c446d228c4b806ae3/librt-0.7.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f11b300027ce19a34f6d24ebb0a25fd0e24a9d53353225a5c1e6cadbf2916b2e", size = 192038, upload-time = "2026-01-14T12:55:27.208Z" }, + { url = "https://files.pythonhosted.org/packages/06/bb/6f4c650253704279c3a214dad188101d1b5ea23be0606628bc6739456624/librt-0.7.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4adc73614f0d3c97874f02f2c7fd2a27854e7e24ad532ea6b965459c5b757eca", size = 186006, upload-time = "2026-01-14T12:55:28.594Z" }, + { url = "https://files.pythonhosted.org/packages/dc/00/1c409618248d43240cadf45f3efb866837fa77e9a12a71481912135eb481/librt-0.7.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60c299e555f87e4c01b2eca085dfccda1dde87f5a604bb45c2906b8305819a93", size = 206888, upload-time = "2026-01-14T12:55:30.214Z" }, + { url = "https://files.pythonhosted.org/packages/d9/83/b2cfe8e76ff5c1c77f8a53da3d5de62d04b5ebf7cf913e37f8bca43b5d07/librt-0.7.8-cp313-cp313-win32.whl", hash = "sha256:b09c52ed43a461994716082ee7d87618096851319bf695d57ec123f2ab708951", size = 44126, upload-time = "2026-01-14T12:55:31.44Z" }, + { url = "https://files.pythonhosted.org/packages/a9/0b/c59d45de56a51bd2d3a401fc63449c0ac163e4ef7f523ea8b0c0dee86ec5/librt-0.7.8-cp313-cp313-win_amd64.whl", hash = "sha256:f8f4a901a3fa28969d6e4519deceab56c55a09d691ea7b12ca830e2fa3461e34", size = 50262, upload-time = "2026-01-14T12:55:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b9/973455cec0a1ec592395250c474164c4a58ebf3e0651ee920fef1a2623f1/librt-0.7.8-cp313-cp313-win_arm64.whl", hash = "sha256:43d4e71b50763fcdcf64725ac680d8cfa1706c928b844794a7aa0fa9ac8e5f09", size = 43600, upload-time = "2026-01-14T12:55:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/1a/73/fa8814c6ce2d49c3827829cadaa1589b0bf4391660bd4510899393a23ebc/librt-0.7.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:be927c3c94c74b05128089a955fba86501c3b544d1d300282cc1b4bd370cb418", size = 57049, upload-time = "2026-01-14T12:55:35.056Z" }, + { url = "https://files.pythonhosted.org/packages/53/fe/f6c70956da23ea235fd2e3cc16f4f0b4ebdfd72252b02d1164dd58b4e6c3/librt-0.7.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7b0803e9008c62a7ef79058233db7ff6f37a9933b8f2573c05b07ddafa226611", size = 58689, upload-time = "2026-01-14T12:55:36.078Z" }, + { url = "https://files.pythonhosted.org/packages/1f/4d/7a2481444ac5fba63050d9abe823e6bc16896f575bfc9c1e5068d516cdce/librt-0.7.8-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:79feb4d00b2a4e0e05c9c56df707934f41fcb5fe53fd9efb7549068d0495b758", size = 166808, upload-time = "2026-01-14T12:55:37.595Z" }, + { url = "https://files.pythonhosted.org/packages/ac/3c/10901d9e18639f8953f57c8986796cfbf4c1c514844a41c9197cf87cb707/librt-0.7.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9122094e3f24aa759c38f46bd8863433820654927370250f460ae75488b66ea", size = 175614, upload-time = "2026-01-14T12:55:38.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/01/5cbdde0951a5090a80e5ba44e6357d375048123c572a23eecfb9326993a7/librt-0.7.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e03bea66af33c95ce3addf87a9bf1fcad8d33e757bc479957ddbc0e4f7207ac", size = 189955, upload-time = "2026-01-14T12:55:39.939Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b4/e80528d2f4b7eaf1d437fcbd6fc6ba4cbeb3e2a0cb9ed5a79f47c7318706/librt-0.7.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1ade7f31675db00b514b98f9ab9a7698c7282dad4be7492589109471852d398", size = 189370, upload-time = "2026-01-14T12:55:41.057Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ab/938368f8ce31a9787ecd4becb1e795954782e4312095daf8fd22420227c8/librt-0.7.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a14229ac62adcf1b90a15992f1ab9c69ae8b99ffb23cb64a90878a6e8a2f5b81", size = 183224, upload-time = "2026-01-14T12:55:42.328Z" }, + { url = "https://files.pythonhosted.org/packages/3c/10/559c310e7a6e4014ac44867d359ef8238465fb499e7eb31b6bfe3e3f86f5/librt-0.7.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5bcaaf624fd24e6a0cb14beac37677f90793a96864c67c064a91458611446e83", size = 203541, upload-time = "2026-01-14T12:55:43.501Z" }, + { url = "https://files.pythonhosted.org/packages/f8/db/a0db7acdb6290c215f343835c6efda5b491bb05c3ddc675af558f50fdba3/librt-0.7.8-cp314-cp314-win32.whl", hash = "sha256:7aa7d5457b6c542ecaed79cec4ad98534373c9757383973e638ccced0f11f46d", size = 40657, upload-time = "2026-01-14T12:55:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/72/e0/4f9bdc2a98a798511e81edcd6b54fe82767a715e05d1921115ac70717f6f/librt-0.7.8-cp314-cp314-win_amd64.whl", hash = "sha256:3d1322800771bee4a91f3b4bd4e49abc7d35e65166821086e5afd1e6c0d9be44", size = 46835, upload-time = "2026-01-14T12:55:45.655Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3d/59c6402e3dec2719655a41ad027a7371f8e2334aa794ed11533ad5f34969/librt-0.7.8-cp314-cp314-win_arm64.whl", hash = "sha256:5363427bc6a8c3b1719f8f3845ea53553d301382928a86e8fab7984426949bce", size = 39885, upload-time = "2026-01-14T12:55:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9c/2481d80950b83085fb14ba3c595db56330d21bbc7d88a19f20165f3538db/librt-0.7.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ca916919793a77e4a98d4a1701e345d337ce53be4a16620f063191f7322ac80f", size = 59161, upload-time = "2026-01-14T12:55:48.45Z" }, + { url = "https://files.pythonhosted.org/packages/96/79/108df2cfc4e672336765d54e3ff887294c1cc36ea4335c73588875775527/librt-0.7.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:54feb7b4f2f6706bb82325e836a01be805770443e2400f706e824e91f6441dde", size = 61008, upload-time = "2026-01-14T12:55:49.527Z" }, + { url = "https://files.pythonhosted.org/packages/46/f2/30179898f9994a5637459d6e169b6abdc982012c0a4b2d4c26f50c06f911/librt-0.7.8-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:39a4c76fee41007070f872b648cc2f711f9abf9a13d0c7162478043377b52c8e", size = 187199, upload-time = "2026-01-14T12:55:50.587Z" }, + { url = "https://files.pythonhosted.org/packages/b4/da/f7563db55cebdc884f518ba3791ad033becc25ff68eb70902b1747dc0d70/librt-0.7.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac9c8a458245c7de80bc1b9765b177055efff5803f08e548dd4bb9ab9a8d789b", size = 198317, upload-time = "2026-01-14T12:55:51.991Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6c/4289acf076ad371471fa86718c30ae353e690d3de6167f7db36f429272f1/librt-0.7.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b67aa7eff150f075fda09d11f6bfb26edffd300f6ab1666759547581e8f666", size = 210334, upload-time = "2026-01-14T12:55:53.682Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7f/377521ac25b78ac0a5ff44127a0360ee6d5ddd3ce7327949876a30533daa/librt-0.7.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:535929b6eff670c593c34ff435d5440c3096f20fa72d63444608a5aef64dd581", size = 211031, upload-time = "2026-01-14T12:55:54.827Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b1/e1e96c3e20b23d00cf90f4aad48f0deb4cdfec2f0ed8380d0d85acf98bbf/librt-0.7.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:63937bd0f4d1cb56653dc7ae900d6c52c41f0015e25aaf9902481ee79943b33a", size = 204581, upload-time = "2026-01-14T12:55:56.811Z" }, + { url = "https://files.pythonhosted.org/packages/43/71/0f5d010e92ed9747e14bef35e91b6580533510f1e36a8a09eb79ee70b2f0/librt-0.7.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf243da9e42d914036fd362ac3fa77d80a41cadcd11ad789b1b5eec4daaf67ca", size = 224731, upload-time = "2026-01-14T12:55:58.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f0/07fb6ab5c39a4ca9af3e37554f9d42f25c464829254d72e4ebbd81da351c/librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365", size = 41173, upload-time = "2026-01-14T12:55:59.315Z" }, + { url = "https://files.pythonhosted.org/packages/24/d4/7e4be20993dc6a782639625bd2f97f3c66125c7aa80c82426956811cfccf/librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32", size = 47668, upload-time = "2026-01-14T12:56:00.261Z" }, + { url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" }, +] + +[[package]] +name = "mypy" +version = "1.19.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" }, + { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" }, + { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" }, + { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" }, + { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" }, + { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, + { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, + { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, + { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, + { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, + { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, + { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, + { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, + { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, + { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, + { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, + { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, + { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, + { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, + { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] diff --git a/.vscode/settings.json b/.vscode/settings.json --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,14 @@ "eslint.nodePath": "./node_modules", "eslint.workingDirectories": [{ "pattern": "./packages/*/" }], "oxc.fmt.configPath": ".oxfmtrc.json", + "search.exclude": { + "**/*-lock.yaml": true, + "**/*.log": true, + "**/*.map": true, + "**/*.mjs": true, + "**/*.mts": true, + "**/*.tsbuildinfo": true + }, "typescript.preferences.autoImportFileExcludePatterns": ["dist/**"], "typescript.preferences.autoImportSpecifierExcludeRegexes": ["^(node:)?os$"], "typescript.tsdk": "node_modules/typescript/lib", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,10 @@ node-version: ${{ matrix.node-version }} cache: pnpm + - uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/packages/openapi-python/package.json b/packages/openapi-python/package.json --- a/packages/openapi-python/package.json +++ b/packages/openapi-python/package.json @@ -60,7 +60,8 @@ "test:update": "vitest watch --update", "test:watch": "vitest watch", "test": "vitest run", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "typecheck:next": "tsc --noEmit && uv run mypy src/ts-python/__snapshots__" }, "dependencies": { "@hey-api/codegen-core": "workspace:*", diff --git a/packages/openapi-python/bin/run.cmd b/packages/openapi-python/bin/run.cmd new file mode 100644 --- /dev/null +++ b/packages/openapi-python/bin/run.cmd @@ -0,0 +1,3 @@ +@echo off +node "%~dp0\run.js" %* + diff --git a/packages/openapi-python/bin/run.js b/packages/openapi-python/bin/run.js new file mode 100644 --- /dev/null +++ b/packages/openapi-python/bin/run.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node +import { spawnSync } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const target = path.join(__dirname, '..', 'dist', 'run.mjs'); + +if (!fs.existsSync(target)) { + console.error('openapi-python not built (expect dist/run.mjs)'); + process.exit(1); +} + +const res = spawnSync(process.execPath, [target, ...process.argv.slice(2)], { + stdio: 'inherit', +}); +process.exit(res.status ?? 0); diff --git a/packages/openapi-python/src/createClient.ts b/packages/openapi-python/src/createClient.ts --- a/packages/openapi-python/src/createClient.ts +++ b/packages/openapi-python/src/createClient.ts @@ -21,7 +21,7 @@ import { postProcessors } from './config/output/postprocess'; import type { Config } from './config/types'; import { generateOutput } from './generate/output'; -// import { TypeScriptRenderer } from './ts-dsl'; +// import { TypeScriptRenderer } from './py-dsl'; export async function createClient({ config, diff --git a/packages/openapi-python/src/py-dsl/index.ts b/packages/openapi-python/src/py-dsl/index.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/py-dsl/index.ts diff --git a/packages/openapi-python/src/ts-python/index.ts b/packages/openapi-python/src/ts-python/index.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/index.ts @@ -0,0 +1,10 @@ +import { factory } from './nodes/factory'; +import { PyNodeKind } from './nodes/kinds'; +import { createPrinter, printAst } from './printer'; + +export const py = { + PyNodeKind, + createPrinter, + factory, + printAst, +} as const; diff --git a/packages/openapi-python/src/ts-python/printer.ts b/packages/openapi-python/src/ts-python/printer.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/printer.ts @@ -0,0 +1,403 @@ +import type { PyNode } from './nodes/base'; +import { PyNodeKind } from './nodes/kinds'; + +export interface PyPrinterOptions { + indentSize?: number; +} + +export function createPrinter(options?: PyPrinterOptions) { + const indentSize = options?.indentSize ?? 4; + + let indentLevel = 0; + + function processComments( + parts: Array, + lines: ReadonlyArray, + indent?: boolean, + ): void { + if (indent) indentLevel += 1; + parts.push(...lines.map((line) => printLine(`# ${line}`))); + if (indent) indentLevel -= 1; + } + + function printLine(line: string): string { + return ' '.repeat(indentLevel * indentSize) + line; + } + + function printNode(node: PyNode): string { + const parts: Array = []; + + if (node.leadingComments) { + processComments(parts, node.leadingComments); + } + + let indentTrailingComments = false; + + switch (node.kind) { + case PyNodeKind.Assignment: + parts.push(printLine(`${printNode(node.target)} = ${printNode(node.value)}`)); + break; + + case PyNodeKind.AsyncExpression: + parts.push(`async ${printNode(node.expression)}`); + break; + + case PyNodeKind.AugmentedAssignment: + parts.push( + printLine(`${printNode(node.target)} ${node.operator} ${printNode(node.value)}`), + ); + break; + + case PyNodeKind.AwaitExpression: + parts.push(`await ${printNode(node.expression)}`); + break; + + case PyNodeKind.BinaryExpression: + parts.push(`${printNode(node.left)} ${node.operator} ${printNode(node.right)}`); + break; + + case PyNodeKind.Block: + indentLevel += 1; + if (node.statements.length) { + parts.push(...node.statements.map(printNode)); + } else { + parts.push(printLine('pass')); + } + indentLevel -= 1; + break; + + case PyNodeKind.BreakStatement: + parts.push(printLine('break')); + break; + + case PyNodeKind.CallExpression: + parts.push(`${printNode(node.callee)}(${node.args.map(printNode).join(', ')})`); + break; + + case PyNodeKind.ClassDeclaration: { + indentTrailingComments = true; + if (node.decorators) { + parts.push(...node.decorators.map((decorator) => printLine(`@${printNode(decorator)}`))); + } + const bases = node.baseClasses?.length + ? `(${node.baseClasses.map(printNode).join(', ')})` + : ''; + parts.push(printLine(`class ${node.name}${bases}:`)); + if (node.docstring) { + indentLevel += 1; + parts.push(printLine(`"""${node.docstring}"""`), ''); + indentLevel -= 1; + } + parts.push(printNode(node.body)); + break; + } + + case PyNodeKind.Comment: + parts.push(printLine(`# ${node.text}`)); + break; + + case PyNodeKind.ContinueStatement: + parts.push(printLine('continue')); + break; + + case PyNodeKind.DictComprehension: { + const asyncPrefix = node.isAsync ? 'async ' : ''; + const children: Array = [ + `${printNode(node.key)}: ${printNode(node.value)} ${asyncPrefix}for ${printNode(node.target)} in ${printNode(node.iterable)}`, + ]; + if (node.ifs) { + for (const condition of node.ifs) { + children.push(`if ${printNode(condition)}`); + } + } + parts.push(`{${children.join(' ')}}`); + break; + } + + case PyNodeKind.DictExpression: { + const entries = node.entries + .map(({ key, value }) => `${printNode(key)}: ${printNode(value)}`) + .join(', '); + parts.push(`{${entries}}`); + break; + } + + case PyNodeKind.EmptyStatement: + parts.push(''); + break; + + case PyNodeKind.ExpressionStatement: + parts.push(printLine(printNode(node.expression))); + break; + + case PyNodeKind.ForStatement: + parts.push(printLine(`for ${printNode(node.target)} in ${printNode(node.iterable)}:`)); + parts.push(printNode(node.body)); + if (node.elseBlock) { + parts.push(`${printLine('else:')}`); + parts.push(`${printNode(node.elseBlock)}`); + } + break; + + case PyNodeKind.FStringExpression: { + const children = node.parts.map((part) => + typeof part === 'string' ? part : `{${printNode(part)}}`, + ); + parts.push(`f"${children.join('')}"`); + break; + } + + case PyNodeKind.FunctionDeclaration: { + if (node.decorators) { + parts.push(...node.decorators.map((decorator) => printLine(`@${printNode(decorator)}`))); + } + const modifiers = node.modifiers?.map(printNode).join(' ') ?? ''; + const defPrefix = modifiers ? `${modifiers} def` : 'def'; + const parameters = node.parameters.map((parameter) => { + const children: Array = [parameter.name]; + if (parameter.annotation) children.push(`: ${printNode(parameter.annotation)}`); + if (parameter.defaultValue) children.push(` = ${printNode(parameter.defaultValue)}`); + return children.join(''); + }); + const returnAnnotation = node.returnType ? ` -> ${printNode(node.returnType)}` : ''; + parts.push( + printLine(`${defPrefix} ${node.name}(${parameters.join(', ')})${returnAnnotation}:`), + ); + if (node.docstring) { + indentLevel += 1; + parts.push(printLine(`"""${node.docstring}"""`), ''); + indentLevel -= 1; + } + parts.push(printNode(node.body)); + break; + } + + case PyNodeKind.GeneratorExpression: { + const asyncPrefix = node.isAsync ? 'async ' : ''; + const children: Array = [ + `${printNode(node.element)} ${asyncPrefix}for ${printNode(node.target)} in ${printNode(node.iterable)}`, + ]; + if (node.ifs) { + for (const condition of node.ifs) { + children.push(`if ${printNode(condition)}`); + } + } + parts.push(`(${children.join(' ')})`); + break; + } + + case PyNodeKind.Identifier: + parts.push(node.name); + break; + + case PyNodeKind.IfStatement: + parts.push(printLine(`if ${printNode(node.condition)}:`)); + parts.push(`${printNode(node.thenBlock)}`); + if (node.elseBlock) { + parts.push(`${printLine('else:')}`); + parts.push(`${printNode(node.elseBlock)}`); + } + break; + + case PyNodeKind.ImportStatement: { + const fromPrefix = node.isFrom ? `from ${node.module} ` : ''; + if (fromPrefix) { + if (node.names && node.names.length > 0) { + const imports = node.names + .map(({ alias, name }) => (alias ? `${name} as ${alias}` : name)) + .join(', '); + parts.push(printLine(`${fromPrefix}import ${imports}`)); + } else { + parts.push(printLine(`${fromPrefix}import *`)); + } + } else { + if (node.names && node.names.length > 0) { + const imports = node.names + .map(({ alias, name }) => (alias ? `${name} as ${alias}` : name)) + .join(', '); + parts.push(printLine(`import ${imports}`)); + } else { + parts.push(printLine(`import ${node.module}`)); + } + } + break; + } + + case PyNodeKind.LambdaExpression: { + const parameters = node.parameters.map((parameter) => { + const children: Array = [parameter.name]; + if (parameter.annotation) children.push(`: ${printNode(parameter.annotation)}`); + if (parameter.defaultValue) children.push(` = ${printNode(parameter.defaultValue)}`); + return children.join(''); + }); + parts.push(`lambda ${parameters.join(', ')}: ${printNode(node.expression)}`); + break; + } + + case PyNodeKind.ListComprehension: { + const asyncPrefix = node.isAsync ? 'async ' : ''; + const children: Array = [ + `${printNode(node.element)} ${asyncPrefix}for ${printNode(node.target)} in ${printNode(node.iterable)}`, + ]; + if (node.ifs) { + for (const condition of node.ifs) { + children.push(`if ${printNode(condition)}`); + } + } + parts.push(`[${children.join(' ')}]`); + break; + } + + case PyNodeKind.ListExpression: + parts.push(`[${node.elements.map(printNode).join(', ')}]`); + break; + + case PyNodeKind.Literal: + if (typeof node.value === 'string') { + parts.push(`"${node.value}"`); + } else if (typeof node.value === 'boolean') { + parts.push(node.value ? 'True' : 'False'); + } else if (node.value === null) { + parts.push('None'); + } else { + parts.push(String(node.value)); + } + break; + + case PyNodeKind.MemberExpression: + parts.push(`${printNode(node.object)}.${printNode(node.member)}`); + break; + + case PyNodeKind.RaiseStatement: + if (node.expression) { + parts.push(printLine(`raise ${printNode(node.expression)}`)); + } else { + parts.push(printLine('raise')); + } + break; + + case PyNodeKind.ReturnStatement: + if (node.expression) { + parts.push(printLine(`return ${printNode(node.expression)}`)); + } else { + parts.push(printLine('return')); + } + break; + + case PyNodeKind.SetComprehension: { + const asyncPrefix = node.isAsync ? 'async ' : ''; + const children: Array = [ + `${printNode(node.element)} ${asyncPrefix}for ${printNode(node.target)} in ${printNode(node.iterable)}`, + ]; + if (node.ifs) { + for (const condition of node.ifs) { + children.push(`if ${printNode(condition)}`); + } + } + parts.push(`{${children.join(' ')}}`); + break; + } + + case PyNodeKind.SetExpression: { + if (!node.elements.length) { + parts.push('set()'); + } else { + parts.push(`{${node.elements.map(printNode).join(', ')}}`); + } + break; + } + + case PyNodeKind.SourceFile: + if (node.docstring) { + parts.push(printLine(`"""${node.docstring}"""`), ''); + } + parts.push(...node.statements.map(printNode)); + break; + + case PyNodeKind.TryStatement: { + parts.push(printLine('try:'), printNode(node.tryBlock)); + if (node.exceptClauses) { + for (const clause of node.exceptClauses) { + const type = clause.exceptionType ? ` ${printNode(clause.exceptionType)}` : ''; + const name = clause.exceptionName ? ` as ${printNode(clause.exceptionName)}` : ''; + parts.push(printLine(`except${type}${name}:`), printNode(clause.block)); + } + } + if (node.elseBlock) { + parts.push(printLine(`else:`), printNode(node.elseBlock)); + } + if (node.finallyBlock) { + parts.push(printLine(`finally:`), printNode(node.finallyBlock)); + } + break; + } + + case PyNodeKind.TupleExpression: { + // Single-element tuple needs trailing comma + const trailingComma = node.elements.length === 1 ? ',' : ''; + parts.push(`(${node.elements.map(printNode).join(', ')}${trailingComma})`); + break; + } + + case PyNodeKind.WhileStatement: { + parts.push(printLine(`while ${printNode(node.condition)}:`)); + parts.push(printNode(node.body)); + if (node.elseBlock) { + parts.push(`${printLine('else:')}`); + parts.push(`${printNode(node.elseBlock)}`); + } + break; + } + + case PyNodeKind.WithStatement: { + const modifiers = node.modifiers?.map(printNode).join(' ') ?? ''; + const withPrefix = modifiers ? `${modifiers} with` : 'with'; + const items = node.items + .map((item) => + item.alias + ? `${printNode(item.contextExpr)} as ${printNode(item.alias)}` + : printNode(item.contextExpr), + ) + .join(', '); + parts.push(printLine(`${withPrefix} ${items}:`)); + parts.push(printNode(node.body)); + break; + } + + case PyNodeKind.YieldExpression: + if (node.value) { + parts.push(`yield ${printNode(node.value)}`); + } else { + parts.push('yield'); + } + break; + + case PyNodeKind.YieldFromExpression: + parts.push(`yield from ${printNode(node.expression)}`); + break; + + default: + // @ts-expect-error + throw new Error(`Unsupported node kind: ${node.kind}`); + } + + if (node.trailingComments) { + processComments(parts, node.trailingComments, indentTrailingComments); + } + + return parts.join('\n'); + } + + function printFile(node: PyNode): string { + const parts: Array = [printNode(node), '']; + return parts.join('\n'); + } + + return { + printFile, + }; +} + +export function printAst(node: PyNode): string { + return JSON.stringify(node, null, 2); +} diff --git a/packages/openapi-python/src/ts-python/__snapshots__/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/__init__.py diff --git a/packages/openapi-python/src/ts-python/__tests__/constants.ts b/packages/openapi-python/src/ts-python/__tests__/constants.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/constants.ts @@ -0,0 +1,4 @@ +import path from 'node:path'; + +export const snapshotsDir = path.join(__dirname, '..', '__snapshots__'); +export const tmpDir = path.join(__dirname, '..', '.tmp'); diff --git a/packages/openapi-python/src/ts-python/__tests__/globalTeardown.ts b/packages/openapi-python/src/ts-python/__tests__/globalTeardown.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/globalTeardown.ts @@ -0,0 +1,7 @@ +import fs from 'node:fs'; + +import { tmpDir } from './constants'; + +export function teardown() { + fs.rmSync(tmpDir, { force: true, recursive: true }); +} diff --git a/packages/openapi-python/src/ts-python/nodes/base.ts b/packages/openapi-python/src/ts-python/nodes/base.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/base.ts @@ -0,0 +1,13 @@ +import type { PyExpression } from './expression'; +import type { PyNodeKind } from './kinds'; +import type { PyStatement } from './statement'; +import type { PyBlock } from './statements/block'; +import type { PySourceFile } from './structure/sourceFile'; + +export interface PyNodeBase { + kind: PyNodeKind; + leadingComments?: ReadonlyArray; + trailingComments?: ReadonlyArray; +} + +export type PyNode = PyBlock | PyExpression | PySourceFile | PyStatement; diff --git a/packages/openapi-python/src/ts-python/nodes/comprehension.ts b/packages/openapi-python/src/ts-python/nodes/comprehension.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/comprehension.ts @@ -0,0 +1,14 @@ +import type { PyNodeBase } from './base'; +import type { PyExpression } from './expression'; +import type { PyDictComprehension } from './expressions/comprehensions/dict'; +import type { PyListComprehension } from './expressions/comprehensions/list'; +import type { PySetComprehension } from './expressions/comprehensions/set'; + +export type PyComprehension = PyDictComprehension | PyListComprehension | PySetComprehension; + +export interface PyComprehensionNode extends PyNodeBase { + ifs?: ReadonlyArray; + isAsync?: boolean; + iterable: PyExpression; + target: PyExpression; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expression.ts b/packages/openapi-python/src/ts-python/nodes/expression.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expression.ts @@ -0,0 +1,36 @@ +import type { PyComprehension } from './comprehension'; +import type { PyAsyncExpression } from './expressions/async'; +import type { PyAwaitExpression } from './expressions/await'; +import type { PyBinaryExpression } from './expressions/binary'; +import type { PyCallExpression } from './expressions/call'; +import type { PyDictExpression } from './expressions/dict'; +import type { PyFStringExpression } from './expressions/fString'; +import type { PyGeneratorExpression } from './expressions/generator'; +import type { PyIdentifier } from './expressions/identifier'; +import type { PyLambdaExpression } from './expressions/lambda'; +import type { PyListExpression } from './expressions/list'; +import type { PyLiteral } from './expressions/literal'; +import type { PyMemberExpression } from './expressions/member'; +import type { PySetExpression } from './expressions/set'; +import type { PyTupleExpression } from './expressions/tuple'; +import type { PyYieldExpression } from './expressions/yield'; +import type { PyYieldFromExpression } from './expressions/yieldFrom'; + +export type PyExpression = + | PyAsyncExpression + | PyAwaitExpression + | PyBinaryExpression + | PyCallExpression + | PyComprehension + | PyDictExpression + | PyFStringExpression + | PyGeneratorExpression + | PyIdentifier + | PyLambdaExpression + | PyListExpression + | PyLiteral + | PyMemberExpression + | PySetExpression + | PyTupleExpression + | PyYieldExpression + | PyYieldFromExpression; diff --git a/packages/openapi-python/src/ts-python/nodes/factory.ts b/packages/openapi-python/src/ts-python/nodes/factory.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/factory.ts @@ -0,0 +1,85 @@ +import { createClassDeclaration } from './declarations/class'; +import { createFunctionDeclaration } from './declarations/function'; +import { createFunctionParameter } from './declarations/functionParameter'; +import { createAsyncExpression } from './expressions/async'; +import { createAwaitExpression } from './expressions/await'; +import { createBinaryExpression } from './expressions/binary'; +import { createCallExpression } from './expressions/call'; +import { createDictComprehension } from './expressions/comprehensions/dict'; +import { createListComprehension } from './expressions/comprehensions/list'; +import { createSetComprehension } from './expressions/comprehensions/set'; +import { createDictExpression } from './expressions/dict'; +import { createFStringExpression } from './expressions/fString'; +import { createGeneratorExpression } from './expressions/generator'; +import { createIdentifier } from './expressions/identifier'; +import { createLambdaExpression } from './expressions/lambda'; +import { createListExpression } from './expressions/list'; +import { createLiteral } from './expressions/literal'; +import { createMemberExpression } from './expressions/member'; +import { createSetExpression } from './expressions/set'; +import { createTupleExpression } from './expressions/tuple'; +import { createYieldExpression } from './expressions/yield'; +import { createYieldFromExpression } from './expressions/yieldFrom'; +import { createAssignment } from './statements/assignment'; +import { createAugmentedAssignment } from './statements/augmentedAssignment'; +import { createBlock } from './statements/block'; +import { createBreakStatement } from './statements/break'; +import { createContinueStatement } from './statements/continue'; +import { createEmptyStatement } from './statements/empty'; +import { createExceptClause } from './statements/except'; +import { createExpressionStatement } from './statements/expression'; +import { createForStatement } from './statements/for'; +import { createIfStatement } from './statements/if'; +import { createImportStatement } from './statements/import'; +import { createRaiseStatement } from './statements/raise'; +import { createReturnStatement } from './statements/return'; +import { createTryStatement } from './statements/try'; +import { createWhileStatement } from './statements/while'; +import { createWithStatement } from './statements/with'; +import { createWithItem } from './statements/withItem'; +import { createComment } from './structure/comment'; +import { createSourceFile } from './structure/sourceFile'; + +export const factory = { + createAssignment, + createAsyncExpression, + createAugmentedAssignment, + createAwaitExpression, + createBinaryExpression, + createBlock, + createBreakStatement, + createCallExpression, + createClassDeclaration, + createComment, + createContinueStatement, + createDictComprehension, + createDictExpression, + createEmptyStatement, + createExceptClause, + createExpressionStatement, + createFStringExpression, + createForStatement, + createFunctionDeclaration, + createFunctionParameter, + createGeneratorExpression, + createIdentifier, + createIfStatement, + createImportStatement, + createLambdaExpression, + createListComprehension, + createListExpression, + createLiteral, + createMemberExpression, + createRaiseStatement, + createReturnStatement, + createSetComprehension, + createSetExpression, + createSourceFile, + createTryStatement, + createTupleExpression, + createWhileStatement, + createWithItem, + createWithStatement, + createYieldExpression, + createYieldFromExpression, +}; diff --git a/packages/openapi-python/src/ts-python/nodes/kinds.ts b/packages/openapi-python/src/ts-python/nodes/kinds.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/kinds.ts @@ -0,0 +1,43 @@ +export enum PyNodeKind { + Assignment = 'Assignment', + AsyncExpression = 'AsyncExpression', + AugmentedAssignment = 'AugmentedAssignment', + AwaitExpression = 'AwaitExpression', + BinaryExpression = 'BinaryExpression', + Block = 'Block', + BreakStatement = 'BreakStatement', + CallExpression = 'CallExpression', + ClassDeclaration = 'ClassDeclaration', + Comment = 'Comment', + ContinueStatement = 'ContinueStatement', + DictComprehension = 'DictComprehension', + DictExpression = 'DictExpression', + EmptyStatement = 'EmptyStatement', + ExceptClause = 'ExceptClause', + ExpressionStatement = 'ExpressionStatement', + FStringExpression = 'FStringExpression', + ForStatement = 'ForStatement', + FunctionDeclaration = 'FunctionDeclaration', + FunctionParameter = 'FunctionParameter', + GeneratorExpression = 'GeneratorExpression', + Identifier = 'Identifier', + IfStatement = 'IfStatement', + ImportStatement = 'ImportStatement', + LambdaExpression = 'LambdaExpression', + ListComprehension = 'ListComprehension', + ListExpression = 'ListExpression', + Literal = 'Literal', + MemberExpression = 'MemberExpression', + RaiseStatement = 'RaiseStatement', + ReturnStatement = 'ReturnStatement', + SetComprehension = 'SetComprehension', + SetExpression = 'SetExpression', + SourceFile = 'SourceFile', + TryStatement = 'TryStatement', + TupleExpression = 'TupleExpression', + WhileStatement = 'WhileStatement', + WithItem = 'WithItem', + WithStatement = 'WithStatement', + YieldExpression = 'YieldExpression', + YieldFromExpression = 'YieldFromExpression', +} diff --git a/packages/openapi-python/src/ts-python/nodes/statement.ts b/packages/openapi-python/src/ts-python/nodes/statement.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statement.ts @@ -0,0 +1,36 @@ +import type { PyClassDeclaration } from './declarations/class'; +import type { PyFunctionDeclaration } from './declarations/function'; +import type { PyAssignment } from './statements/assignment'; +import type { PyAugmentedAssignment } from './statements/augmentedAssignment'; +import type { PyBreakStatement } from './statements/break'; +import type { PyContinueStatement } from './statements/continue'; +import type { PyEmptyStatement } from './statements/empty'; +import type { PyExpressionStatement } from './statements/expression'; +import type { PyForStatement } from './statements/for'; +import type { PyIfStatement } from './statements/if'; +import type { PyImportStatement } from './statements/import'; +import type { PyRaiseStatement } from './statements/raise'; +import type { PyReturnStatement } from './statements/return'; +import type { PyTryStatement } from './statements/try'; +import type { PyWhileStatement } from './statements/while'; +import type { PyWithStatement } from './statements/with'; +import type { PyComment } from './structure/comment'; + +export type PyStatement = + | PyAssignment + | PyAugmentedAssignment + | PyBreakStatement + | PyClassDeclaration + | PyComment + | PyContinueStatement + | PyEmptyStatement + | PyExpressionStatement + | PyForStatement + | PyFunctionDeclaration + | PyIfStatement + | PyImportStatement + | PyRaiseStatement + | PyReturnStatement + | PyTryStatement + | PyWhileStatement + | PyWithStatement; diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/__init__.py diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/utils.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/utils.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/utils.ts @@ -0,0 +1,65 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { expect } from 'vitest'; + +import { py } from '../../index'; +import type { PySourceFile } from '../../nodes/structure/sourceFile'; +import { snapshotsDir, tmpDir } from '../constants'; + +function getCallerFile(): string { + const error = new Error(); + const stack = (error.stack ?? '').split('\n'); + const callerLine = stack.find((line) => line.includes('.test.ts')); + if (!callerLine) { + throw new Error('Could not find test file in stack trace'); + } + const match = callerLine.match(/\(([^)]+)\)/) || callerLine.match(/at (.+):\d+:\d+/); + if (!match?.[1]) { + throw new Error('Could not extract file path'); + } + return match[1]; +} + +function ensureInitFiles(dir: string, rootDir: string): void { + let current = dir; + while (current.startsWith(rootDir) && current !== rootDir) { + const initPath = path.join(current, '__init__.py'); + if (!fs.existsSync(initPath)) { + fs.writeFileSync(initPath, ''); + } + current = path.dirname(current); + } + + const rootInit = path.join(rootDir, '__init__.py'); + if (!fs.existsSync(rootInit)) { + fs.writeFileSync(rootInit, ''); + } +} + +export async function assertPrintedMatchesSnapshot( + file: PySourceFile, + filename: string, +): Promise { + const result = py.createPrinter().printFile(file); + + const caller = getCallerFile(); + const relPath = path + .relative(path.join(process.cwd(), 'src', 'ts-python', '__tests__'), caller) + .replace(/\.test\.ts$/, ''); + const outputPath = path.join(tmpDir, relPath, filename); + const outputDir = path.dirname(outputPath); + + fs.mkdirSync(outputDir, { recursive: true }); + fs.writeFileSync(outputPath, result); + + ensureInitFiles(outputDir, tmpDir); + + const snapshotPath = path.join(snapshotsDir, relPath, filename); + + const snapshotDir = path.dirname(snapshotPath); + fs.mkdirSync(snapshotDir, { recursive: true }); + ensureInitFiles(snapshotDir, snapshotsDir); + + await expect(result).toMatchFileSnapshot(snapshotPath); +} diff --git a/packages/openapi-python/src/ts-python/nodes/declarations/class.ts b/packages/openapi-python/src/ts-python/nodes/declarations/class.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/declarations/class.ts @@ -0,0 +1,36 @@ +import type { PyNode, PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import type { PyBlock } from '../statements/block'; +import { createBlock } from '../statements/block'; + +export interface PyClassDeclaration extends PyNodeBase { + baseClasses?: ReadonlyArray; + body: PyBlock; + decorators?: ReadonlyArray; + docstring?: string; + kind: PyNodeKind.ClassDeclaration; + name: string; +} + +export function createClassDeclaration( + name: string, + body: ReadonlyArray, + decorators?: ReadonlyArray, + baseClasses?: ReadonlyArray, + docstring?: string, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyClassDeclaration { + return { + baseClasses, + body: createBlock(body), + decorators, + docstring, + kind: PyNodeKind.ClassDeclaration, + leadingComments, + name, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/declarations/function.ts b/packages/openapi-python/src/ts-python/nodes/declarations/function.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/declarations/function.ts @@ -0,0 +1,43 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import type { PyBlock } from '../statements/block'; +import { createBlock } from '../statements/block'; +import type { PyFunctionParameter } from './functionParameter'; + +export interface PyFunctionDeclaration extends PyNodeBase { + body: PyBlock; + decorators?: ReadonlyArray; + docstring?: string; + kind: PyNodeKind.FunctionDeclaration; + modifiers?: ReadonlyArray; + name: string; + parameters: ReadonlyArray; + returnType?: PyExpression; +} + +export function createFunctionDeclaration( + name: string, + parameters: ReadonlyArray, + returnType: PyExpression | undefined, + body: ReadonlyArray, + decorators?: ReadonlyArray, + docstring?: string, + modifiers?: ReadonlyArray, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyFunctionDeclaration { + return { + body: createBlock(body), + decorators, + docstring, + kind: PyNodeKind.FunctionDeclaration, + leadingComments, + modifiers, + name, + parameters, + returnType, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/declarations/functionParameter.ts b/packages/openapi-python/src/ts-python/nodes/declarations/functionParameter.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/declarations/functionParameter.ts @@ -0,0 +1,27 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyFunctionParameter extends PyNodeBase { + annotation?: PyExpression; + defaultValue?: PyExpression; + kind: PyNodeKind.FunctionParameter; + name: string; +} + +export function createFunctionParameter( + name: string, + annotation?: PyExpression, + defaultValue?: PyExpression, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyFunctionParameter { + return { + annotation, + defaultValue, + kind: PyNodeKind.FunctionParameter, + leadingComments, + name, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/async.ts b/packages/openapi-python/src/ts-python/nodes/expressions/async.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/async.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyAsyncExpression extends PyNodeBase { + expression: PyExpression; + kind: PyNodeKind.AsyncExpression; +} + +export function createAsyncExpression(expression: PyExpression): PyAsyncExpression { + return { + expression, + kind: PyNodeKind.AsyncExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/await.ts b/packages/openapi-python/src/ts-python/nodes/expressions/await.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/await.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyAwaitExpression extends PyNodeBase { + expression: PyExpression; + kind: PyNodeKind.AwaitExpression; +} + +export function createAwaitExpression(expression: PyExpression): PyAwaitExpression { + return { + expression, + kind: PyNodeKind.AwaitExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/binary.ts b/packages/openapi-python/src/ts-python/nodes/expressions/binary.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/binary.ts @@ -0,0 +1,48 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export type PyBinaryOperator = + | '+' + | '-' + | '*' + | '/' + | '//' + | '%' + | '**' + | '==' + | '!=' + | '>' + | '>=' + | '<' + | '<=' + | 'is' + | 'is not' + | 'in' + | 'not in' + | 'and' + | 'or'; + +export interface PyBinaryExpression extends PyNodeBase { + kind: PyNodeKind.BinaryExpression; + left: PyExpression; + operator: PyBinaryOperator; + right: PyExpression; +} + +export function createBinaryExpression( + left: PyExpression, + operator: PyBinaryOperator, + right: PyExpression, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyBinaryExpression { + return { + kind: PyNodeKind.BinaryExpression, + leadingComments, + left, + operator, + right, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/call.ts b/packages/openapi-python/src/ts-python/nodes/expressions/call.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/call.ts @@ -0,0 +1,24 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyCallExpression extends PyNodeBase { + args: ReadonlyArray; + callee: PyExpression; + kind: PyNodeKind.CallExpression; +} + +export function createCallExpression( + callee: PyExpression, + args: ReadonlyArray, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyCallExpression { + return { + args, + callee, + kind: PyNodeKind.CallExpression, + leadingComments, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/dict.ts b/packages/openapi-python/src/ts-python/nodes/expressions/dict.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/dict.ts @@ -0,0 +1,20 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyDictExpression extends PyNodeBase { + entries: ReadonlyArray<{ + key: PyExpression; + value: PyExpression; + }>; + kind: PyNodeKind.DictExpression; +} + +export function createDictExpression( + entries: ReadonlyArray<{ key: PyExpression; value: PyExpression }>, +): PyDictExpression { + return { + entries, + kind: PyNodeKind.DictExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/fString.ts b/packages/openapi-python/src/ts-python/nodes/expressions/fString.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/fString.ts @@ -0,0 +1,21 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyFStringExpression extends PyNodeBase { + kind: PyNodeKind.FStringExpression; + parts: Array; +} + +export function createFStringExpression( + parts: Array, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyFStringExpression { + return { + kind: PyNodeKind.FStringExpression, + leadingComments, + parts, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/generator.ts b/packages/openapi-python/src/ts-python/nodes/expressions/generator.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/generator.ts @@ -0,0 +1,33 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyGeneratorExpression extends PyNodeBase { + element: PyExpression; + ifs?: ReadonlyArray; + isAsync?: boolean; + iterable: PyExpression; + kind: PyNodeKind.GeneratorExpression; + target: PyExpression; +} + +export function createGeneratorExpression( + element: PyExpression, + target: PyExpression, + iterable: PyExpression, + ifs?: ReadonlyArray, + isAsync?: boolean, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyGeneratorExpression { + return { + element, + ifs, + isAsync, + iterable, + kind: PyNodeKind.GeneratorExpression, + leadingComments, + target, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/identifier.ts b/packages/openapi-python/src/ts-python/nodes/expressions/identifier.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/identifier.ts @@ -0,0 +1,20 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyIdentifier extends PyNodeBase { + kind: PyNodeKind.Identifier; + name: string; +} + +export function createIdentifier( + name: string, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyIdentifier { + return { + kind: PyNodeKind.Identifier, + leadingComments, + name, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/lambda.ts b/packages/openapi-python/src/ts-python/nodes/expressions/lambda.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/lambda.ts @@ -0,0 +1,21 @@ +import type { PyNodeBase } from '../base'; +import type { PyFunctionParameter } from '../declarations/functionParameter'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyLambdaExpression extends PyNodeBase { + expression: PyExpression; + kind: PyNodeKind.LambdaExpression; + parameters: ReadonlyArray; +} + +export function createLambdaExpression( + parameters: ReadonlyArray, + expression: PyExpression, +): PyLambdaExpression { + return { + expression, + kind: PyNodeKind.LambdaExpression, + parameters, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/list.ts b/packages/openapi-python/src/ts-python/nodes/expressions/list.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/list.ts @@ -0,0 +1,14 @@ +import type { PyNode, PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyListExpression extends PyNodeBase { + elements: ReadonlyArray; + kind: PyNodeKind.ListExpression; +} + +export function createListExpression(elements: ReadonlyArray): PyListExpression { + return { + elements, + kind: PyNodeKind.ListExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/literal.ts b/packages/openapi-python/src/ts-python/nodes/expressions/literal.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/literal.ts @@ -0,0 +1,22 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export type LiteralValue = string | number | boolean | null; + +export interface PyLiteral extends PyNodeBase { + kind: PyNodeKind.Literal; + value: LiteralValue; +} + +export function createLiteral( + value: LiteralValue, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyLiteral { + return { + kind: PyNodeKind.Literal, + leadingComments, + trailingComments, + value, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/member.ts b/packages/openapi-python/src/ts-python/nodes/expressions/member.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/member.ts @@ -0,0 +1,25 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyIdentifier } from './identifier'; + +export interface PyMemberExpression extends PyNodeBase { + kind: PyNodeKind.MemberExpression; + member: PyIdentifier; + object: PyExpression; +} + +export function createMemberExpression( + object: PyExpression, + member: PyIdentifier, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyMemberExpression { + return { + kind: PyNodeKind.MemberExpression, + leadingComments, + member, + object, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/set.ts b/packages/openapi-python/src/ts-python/nodes/expressions/set.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/set.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PySetExpression extends PyNodeBase { + elements: ReadonlyArray; + kind: PyNodeKind.SetExpression; +} + +export function createSetExpression(elements: ReadonlyArray): PySetExpression { + return { + elements, + kind: PyNodeKind.SetExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/tuple.ts b/packages/openapi-python/src/ts-python/nodes/expressions/tuple.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/tuple.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyTupleExpression extends PyNodeBase { + elements: ReadonlyArray; + kind: PyNodeKind.TupleExpression; +} + +export function createTupleExpression(elements: ReadonlyArray): PyTupleExpression { + return { + elements, + kind: PyNodeKind.TupleExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/yield.ts b/packages/openapi-python/src/ts-python/nodes/expressions/yield.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/yield.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyYieldExpression extends PyNodeBase { + kind: PyNodeKind.YieldExpression; + value?: PyExpression; +} + +export function createYieldExpression(value?: PyExpression): PyYieldExpression { + return { + kind: PyNodeKind.YieldExpression, + value, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/yieldFrom.ts b/packages/openapi-python/src/ts-python/nodes/expressions/yieldFrom.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/yieldFrom.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyYieldFromExpression extends PyNodeBase { + expression: PyExpression; + kind: PyNodeKind.YieldFromExpression; +} + +export function createYieldFromExpression(expression: PyExpression): PyYieldFromExpression { + return { + expression, + kind: PyNodeKind.YieldFromExpression, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/assignment.ts b/packages/openapi-python/src/ts-python/nodes/statements/assignment.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/assignment.ts @@ -0,0 +1,24 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyAssignment extends PyNodeBase { + kind: PyNodeKind.Assignment; + target: PyExpression; + value: PyExpression; +} + +export function createAssignment( + target: PyExpression, + value: PyExpression, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyAssignment { + return { + kind: PyNodeKind.Assignment, + leadingComments, + target, + trailingComments, + value, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/augmentedAssignment.ts b/packages/openapi-python/src/ts-python/nodes/statements/augmentedAssignment.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/augmentedAssignment.ts @@ -0,0 +1,37 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export type PyAugmentedOperator = + | '+=' + | '-=' + | '*=' + | '/=' + | '//=' + | '%=' + | '**=' + | '&=' + | '|=' + | '^=' + | '>>=' + | '<<='; + +export interface PyAugmentedAssignment extends PyNodeBase { + kind: PyNodeKind.AugmentedAssignment; + operator: PyAugmentedOperator; + target: PyExpression; + value: PyExpression; +} + +export function createAugmentedAssignment( + target: PyExpression, + operator: PyAugmentedOperator, + value: PyExpression, +): PyAugmentedAssignment { + return { + kind: PyNodeKind.AugmentedAssignment, + operator, + target, + value, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/block.ts b/packages/openapi-python/src/ts-python/nodes/statements/block.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/block.ts @@ -0,0 +1,21 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; + +export interface PyBlock extends PyNodeBase { + kind: PyNodeKind.Block; + statements: ReadonlyArray; +} + +export function createBlock( + statements: ReadonlyArray, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyBlock { + return { + kind: PyNodeKind.Block, + leadingComments, + statements, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/break.ts b/packages/openapi-python/src/ts-python/nodes/statements/break.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/break.ts @@ -0,0 +1,12 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyBreakStatement extends PyNodeBase { + kind: PyNodeKind.BreakStatement; +} + +export function createBreakStatement(): PyBreakStatement { + return { + kind: PyNodeKind.BreakStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/continue.ts b/packages/openapi-python/src/ts-python/nodes/statements/continue.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/continue.ts @@ -0,0 +1,12 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyContinueStatement extends PyNodeBase { + kind: PyNodeKind.ContinueStatement; +} + +export function createContinueStatement(): PyContinueStatement { + return { + kind: PyNodeKind.ContinueStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/empty.ts b/packages/openapi-python/src/ts-python/nodes/statements/empty.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/empty.ts @@ -0,0 +1,12 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyEmptyStatement extends PyNodeBase { + kind: PyNodeKind.EmptyStatement; +} + +export function createEmptyStatement(): PyEmptyStatement { + return { + kind: PyNodeKind.EmptyStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/except.ts b/packages/openapi-python/src/ts-python/nodes/statements/except.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/except.ts @@ -0,0 +1,26 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import type { PyIdentifier } from '../expressions/identifier'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import { createBlock, type PyBlock } from './block'; + +export interface PyExceptClause extends PyNodeBase { + block: PyBlock; + exceptionName?: PyIdentifier; + exceptionType?: PyExpression; + kind: PyNodeKind.ExceptClause; +} + +export function createExceptClause( + block: ReadonlyArray, + exceptionType?: PyExpression, + exceptionName?: PyIdentifier, +): PyExceptClause { + return { + block: createBlock(block), + exceptionName, + exceptionType, + kind: PyNodeKind.ExceptClause, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/expression.ts b/packages/openapi-python/src/ts-python/nodes/statements/expression.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/expression.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyExpressionStatement extends PyNodeBase { + expression: PyExpression; + kind: PyNodeKind.ExpressionStatement; +} + +export function createExpressionStatement(expression: PyExpression): PyExpressionStatement { + return { + expression, + kind: PyNodeKind.ExpressionStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/for.ts b/packages/openapi-python/src/ts-python/nodes/statements/for.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/for.ts @@ -0,0 +1,29 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import type { PyBlock } from './block'; +import { createBlock } from './block'; + +export interface PyForStatement extends PyNodeBase { + body: PyBlock; + elseBlock?: PyBlock; + iterable: PyExpression; + kind: PyNodeKind.ForStatement; + target: PyExpression; +} + +export function createForStatement( + target: PyExpression, + iterable: PyExpression, + body: ReadonlyArray, + elseBlock?: ReadonlyArray, +): PyForStatement { + return { + body: createBlock(body), + elseBlock: elseBlock ? createBlock(elseBlock) : undefined, + iterable, + kind: PyNodeKind.ForStatement, + target, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/if.ts b/packages/openapi-python/src/ts-python/nodes/statements/if.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/if.ts @@ -0,0 +1,29 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import { createBlock, type PyBlock } from './block'; + +export interface PyIfStatement extends PyNodeBase { + condition: PyExpression; + elseBlock?: PyBlock | PyIfStatement; + kind: PyNodeKind.IfStatement; + thenBlock: PyBlock; +} + +export function createIfStatement( + condition: PyExpression, + thenBlock: ReadonlyArray, + elseBlock?: ReadonlyArray | PyIfStatement, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyIfStatement { + return { + condition, + elseBlock: elseBlock instanceof Array ? createBlock(elseBlock) : elseBlock, + kind: PyNodeKind.IfStatement, + leadingComments, + thenBlock: createBlock(thenBlock), + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/import.ts b/packages/openapi-python/src/ts-python/nodes/statements/import.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/import.ts @@ -0,0 +1,22 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyImportStatement extends PyNodeBase { + isFrom: boolean; + kind: PyNodeKind.ImportStatement; + module: string; + names?: ReadonlyArray<{ alias?: string; name: string }>; +} + +export function createImportStatement( + module: string, + names?: ReadonlyArray<{ alias?: string; name: string }>, + isFrom: boolean = false, +): PyImportStatement { + return { + isFrom, + kind: PyNodeKind.ImportStatement, + module, + names, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/raise.ts b/packages/openapi-python/src/ts-python/nodes/statements/raise.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/raise.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyRaiseStatement extends PyNodeBase { + expression?: PyExpression; + kind: PyNodeKind.RaiseStatement; +} + +export function createRaiseStatement(expression?: PyExpression): PyRaiseStatement { + return { + expression, + kind: PyNodeKind.RaiseStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/return.ts b/packages/openapi-python/src/ts-python/nodes/statements/return.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/return.ts @@ -0,0 +1,15 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyReturnStatement extends PyNodeBase { + expression?: PyExpression; + kind: PyNodeKind.ReturnStatement; +} + +export function createReturnStatement(expression?: PyExpression): PyReturnStatement { + return { + expression, + kind: PyNodeKind.ReturnStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/try.ts b/packages/openapi-python/src/ts-python/nodes/statements/try.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/try.ts @@ -0,0 +1,28 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import { createBlock, type PyBlock } from './block'; +import type { PyExceptClause } from './except'; + +export interface PyTryStatement extends PyNodeBase { + elseBlock?: PyBlock; + exceptClauses?: ReadonlyArray; + finallyBlock?: PyBlock; + kind: PyNodeKind.TryStatement; + tryBlock: PyBlock; +} + +export function createTryStatement( + tryBlock: ReadonlyArray, + exceptClauses?: ReadonlyArray, + elseBlock?: ReadonlyArray, + finallyBlock?: ReadonlyArray, +): PyTryStatement { + return { + elseBlock: elseBlock ? createBlock(elseBlock) : undefined, + exceptClauses, + finallyBlock: finallyBlock ? createBlock(finallyBlock) : undefined, + kind: PyNodeKind.TryStatement, + tryBlock: createBlock(tryBlock), + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/while.ts b/packages/openapi-python/src/ts-python/nodes/statements/while.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/while.ts @@ -0,0 +1,26 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import type { PyBlock } from './block'; +import { createBlock } from './block'; + +export interface PyWhileStatement extends PyNodeBase { + body: PyBlock; + condition: PyExpression; + elseBlock?: PyBlock; + kind: PyNodeKind.WhileStatement; +} + +export function createWhileStatement( + condition: PyExpression, + body: ReadonlyArray, + elseBlock?: ReadonlyArray, +): PyWhileStatement { + return { + body: createBlock(body), + condition, + elseBlock: elseBlock ? createBlock(elseBlock) : undefined, + kind: PyNodeKind.WhileStatement, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/with.ts b/packages/openapi-python/src/ts-python/nodes/statements/with.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/with.ts @@ -0,0 +1,30 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; +import type { PyStatement } from '../statement'; +import { createBlock, type PyBlock } from './block'; +import type { PyWithItem } from './withItem'; + +export interface PyWithStatement extends PyNodeBase { + body: PyBlock; + items: ReadonlyArray; + kind: PyNodeKind.WithStatement; + modifiers?: ReadonlyArray; +} + +export function createWithStatement( + items: ReadonlyArray, + body: ReadonlyArray, + modifiers?: ReadonlyArray, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyWithStatement { + return { + body: createBlock(body), + items, + kind: PyNodeKind.WithStatement, + leadingComments, + modifiers, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/statements/withItem.ts b/packages/openapi-python/src/ts-python/nodes/statements/withItem.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/statements/withItem.ts @@ -0,0 +1,24 @@ +import type { PyNodeBase } from '../base'; +import type { PyExpression } from '../expression'; +import { PyNodeKind } from '../kinds'; + +export interface PyWithItem extends PyNodeBase { + alias?: PyExpression; + contextExpr: PyExpression; + kind: PyNodeKind.WithItem; +} + +export function createWithItem( + contextExpr: PyExpression, + alias?: PyExpression, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PyWithItem { + return { + alias, + contextExpr, + kind: PyNodeKind.WithItem, + leadingComments, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/structure/comment.ts b/packages/openapi-python/src/ts-python/nodes/structure/comment.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/structure/comment.ts @@ -0,0 +1,14 @@ +import type { PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PyComment extends PyNodeBase { + kind: PyNodeKind.Comment; + text: string; +} + +export function createComment(text: string): PyComment { + return { + kind: PyNodeKind.Comment, + text, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/structure/sourceFile.ts b/packages/openapi-python/src/ts-python/nodes/structure/sourceFile.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/structure/sourceFile.ts @@ -0,0 +1,23 @@ +import type { PyNode, PyNodeBase } from '../base'; +import { PyNodeKind } from '../kinds'; + +export interface PySourceFile extends PyNodeBase { + docstring?: string; + kind: PyNodeKind.SourceFile; + statements: ReadonlyArray; +} + +export function createSourceFile( + statements: ReadonlyArray, + docstring?: string, + leadingComments?: ReadonlyArray, + trailingComments?: ReadonlyArray, +): PySourceFile { + return { + docstring, + kind: PyNodeKind.SourceFile, + leadingComments, + statements, + trailingComments, + }; +} diff --git a/packages/openapi-python/src/plugins/@hey-api/sdk/v1/plugin.ts b/packages/openapi-python/src/plugins/@hey-api/sdk/v1/plugin.ts --- a/packages/openapi-python/src/plugins/@hey-api/sdk/v1/plugin.ts +++ b/packages/openapi-python/src/plugins/@hey-api/sdk/v1/plugin.ts @@ -2,4 +2,5 @@ export const handlerV1: HeyApiSdkPlugin['Handler'] = ({ plugin }) => { console.log(plugin); + // plugin.node() }; diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/__init__.py diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/declarations/class.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/declarations/class.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/declarations/class.test.ts @@ -0,0 +1,90 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('class declaration', () => { + it('default', async () => { + const file = py.factory.createSourceFile([py.factory.createClassDeclaration('MyClass', [])]); + await assertPrintedMatchesSnapshot(file, 'default.py'); + }); + + it('with docstring', async () => { + const node = py.factory.createSourceFile([ + py.factory.createClassDeclaration( + 'MyClass', + [], + undefined, + undefined, + 'This is a class docstring', + ), + ]); + await assertPrintedMatchesSnapshot(node, 'with-docstring.py'); + }); + + it('with base class', async () => { + const node = py.factory.createSourceFile([ + py.factory.createClassDeclaration('BaseClass', []), + py.factory.createEmptyStatement(), + py.factory.createClassDeclaration('MyClass', [], undefined, [ + py.factory.createIdentifier('BaseClass'), + ]), + ]); + await assertPrintedMatchesSnapshot(node, 'with-extends.py'); + }); + + it('with method', async () => { + const node = py.factory.createSourceFile([ + py.factory.createClassDeclaration('MyClass', [ + py.factory.createFunctionDeclaration('foo', [], undefined, [ + py.factory.createReturnStatement(py.factory.createLiteral(42)), + ]), + ]), + ]); + await assertPrintedMatchesSnapshot(node, 'with-method.py'); + }); + + it('with decorators', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'my_decorator', + [py.factory.createFunctionParameter('func')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('func'))], + ), + py.factory.createEmptyStatement(), + py.factory.createFunctionDeclaration( + 'another_decorator', + [py.factory.createFunctionParameter('func')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('func'))], + ), + py.factory.createEmptyStatement(), + py.factory.createClassDeclaration( + 'MyClass', + [], + [ + py.factory.createIdentifier('my_decorator'), + py.factory.createIdentifier('another_decorator'), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-decorators.py'); + }); + + it('with method docstring', async () => { + const file = py.factory.createSourceFile([ + py.factory.createClassDeclaration('MyClass', [ + py.factory.createFunctionDeclaration( + 'greet', + [], + undefined, + [], + undefined, + 'Greets the user.', + ), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'with-method-docstring.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/declarations/function.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/declarations/function.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/declarations/function.test.ts @@ -0,0 +1,122 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('function declaration', () => { + it('default', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('greet', [], undefined, []), + ]); + await assertPrintedMatchesSnapshot(file, 'default.py'); + }); + + it('with docstring', async () => { + const node = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'greet', + [], + undefined, + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('Hello'), + ]), + ), + ], + undefined, + 'This function prints a greeting.', + ), + ]); + await assertPrintedMatchesSnapshot(node, 'with-docstring.py'); + }); + + it('with body', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'greet', + [py.factory.createFunctionParameter('name')], + undefined, + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createIdentifier('name'), + ]), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-body.py'); + }); + + it('with decorators', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'my_decorator', + [py.factory.createFunctionParameter('func')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('func'))], + ), + py.factory.createEmptyStatement(), + py.factory.createFunctionDeclaration( + 'another_decorator', + [py.factory.createFunctionParameter('func')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('func'))], + ), + py.factory.createEmptyStatement(), + py.factory.createFunctionDeclaration( + 'greet', + [], + undefined, + [], + [ + py.factory.createIdentifier('my_decorator'), + py.factory.createIdentifier('another_decorator'), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-decorators.py'); + }); + + it('with parameter annotations, defaults, and return type', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'greet', + [ + py.factory.createFunctionParameter( + 'name', + py.factory.createIdentifier('str'), + py.factory.createLiteral('World'), + ), + py.factory.createFunctionParameter( + 'times', + py.factory.createIdentifier('int'), + py.factory.createLiteral(1), + ), + ], + py.factory.createIdentifier('None'), // returnType + [ + py.factory.createForStatement( + py.factory.createIdentifier('i'), + py.factory.createCallExpression(py.factory.createIdentifier('range'), [ + py.factory.createIdentifier('times'), + ]), + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createBinaryExpression( + py.factory.createLiteral('Hello, '), + '+', + py.factory.createIdentifier('name'), + ), + ]), + ), + ], + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-annotations-defaults-return.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/await.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/await.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/await.test.ts @@ -0,0 +1,29 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('await expression', () => { + it('inside async function', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('fetchData', [], undefined, []), + py.factory.createEmptyStatement(), + py.factory.createFunctionDeclaration( + 'main', + [], + undefined, + [ + py.factory.createExpressionStatement( + py.factory.createAwaitExpression( + py.factory.createCallExpression(py.factory.createIdentifier('fetchData'), []), + ), + ), + ], + undefined, + undefined, + [py.factory.createIdentifier('async')], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'inside-function.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/binary.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/binary.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/binary.test.ts @@ -0,0 +1,38 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('binary expression', () => { + it('add', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('a'), py.factory.createLiteral(42)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(84)), + py.factory.createAssignment( + py.factory.createIdentifier('z'), + py.factory.createBinaryExpression( + py.factory.createIdentifier('a'), + '+', + py.factory.createIdentifier('b'), + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'add.py'); + }); + + it('subtract', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('a'), py.factory.createLiteral(42)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(84)), + py.factory.createAssignment( + py.factory.createIdentifier('z'), + py.factory.createBinaryExpression( + py.factory.createIdentifier('a'), + '-', + py.factory.createIdentifier('b'), + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'subtract.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/call.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/call.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/call.test.ts @@ -0,0 +1,15 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('call expression', () => { + it('print', async () => { + const file = py.factory.createSourceFile([ + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('hi'), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'call.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/dict.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/dict.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/dict.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('dict expression', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('person'), + py.factory.createDictExpression([ + { + key: py.factory.createLiteral('name'), + value: py.factory.createLiteral('Alice'), + }, + { + key: py.factory.createLiteral('age'), + value: py.factory.createLiteral(30), + }, + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'dict.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/fString.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/fString.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/fString.test.ts @@ -0,0 +1,41 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('f-string expression', () => { + it('simple interpolation', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('name'), + py.factory.createLiteral('Joe'), + ), + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createFStringExpression(['Hello, ', py.factory.createIdentifier('name'), '!']), + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'simple-interpolation.py'); + }); + + it('with multiple expressions', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('a'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(2)), + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createFStringExpression([ + 'Sum: ', + py.factory.createBinaryExpression( + py.factory.createIdentifier('a'), + '+', + py.factory.createIdentifier('b'), + ), + ]), + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'multiple-expressions.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/generator.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/generator.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/generator.test.ts @@ -0,0 +1,78 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('generator expression', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('x_iter'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createExpressionStatement( + py.factory.createGeneratorExpression( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x_iter'), + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'simple.py'); + }); + + it('with filters', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('x_iter'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createExpressionStatement( + py.factory.createGeneratorExpression( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x_iter'), + [ + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '>', + py.factory.createLiteral(10), + ), + ], + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-filter.py'); + }); + + it('async', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('x_iter'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createExpressionStatement( + py.factory.createGeneratorExpression( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x_iter'), + undefined, + true, + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'async.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/identifier.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/identifier.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/identifier.test.ts @@ -0,0 +1,17 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('identifier expression', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('y'), py.factory.createLiteral(42)), + py.factory.createAssignment( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('y'), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'identifier.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/lambda.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/lambda.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/lambda.test.ts @@ -0,0 +1,42 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('lambda expression', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('x'), py.factory.createLiteral(5)), + py.factory.createExpressionStatement( + py.factory.createLambdaExpression( + [], + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '+', + py.factory.createLiteral(1), + ), + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'simple.py'); + }); + + it('with parameters and default', async () => { + const file = py.factory.createSourceFile([ + py.factory.createExpressionStatement( + py.factory.createLambdaExpression( + [ + py.factory.createFunctionParameter('x'), + py.factory.createFunctionParameter('y', undefined, py.factory.createLiteral(10)), + ], + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '*', + py.factory.createIdentifier('y'), + ), + ), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-params-and-default.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/list.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/list.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/list.test.ts @@ -0,0 +1,20 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('list expression', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('nums'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'list.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/literal.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/literal.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/literal.test.ts @@ -0,0 +1,22 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('literal expression', () => { + it('primitive variables', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('s'), + py.factory.createLiteral('hello'), + ), + py.factory.createAssignment(py.factory.createIdentifier('n'), py.factory.createLiteral(123)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(true)), + py.factory.createAssignment( + py.factory.createIdentifier('none'), + py.factory.createLiteral(null), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'primitive.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/set.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/set.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/set.test.ts @@ -0,0 +1,36 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('set expression', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('foo'), + py.factory.createLiteral('bar'), + ), + py.factory.createAssignment( + py.factory.createIdentifier('emptySet'), + py.factory.createSetExpression([]), + ), + py.factory.createAssignment( + py.factory.createIdentifier('numberSet'), + py.factory.createSetExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createAssignment( + py.factory.createIdentifier('mixedSet'), + py.factory.createSetExpression([ + py.factory.createLiteral('a'), + py.factory.createLiteral(true), + py.factory.createIdentifier('foo'), + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'set.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/tuple.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/tuple.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/tuple.test.ts @@ -0,0 +1,24 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('tuple expression', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('t'), + py.factory.createTupleExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createAssignment( + py.factory.createIdentifier('single'), + py.factory.createTupleExpression([py.factory.createLiteral(42)]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'tuple.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/yield.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/yield.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/yield.test.ts @@ -0,0 +1,46 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('yield expression', () => { + it('without value', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('gen', [], undefined, [ + py.factory.createExpressionStatement(py.factory.createYieldExpression(undefined)), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'default.py'); + }); + + it('with value', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('gen', [], undefined, [ + py.factory.createExpressionStatement( + py.factory.createYieldExpression(py.factory.createLiteral(42)), + ), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'with-value.py'); + }); + + it('from expression', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('iterable'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createEmptyStatement(), + py.factory.createFunctionDeclaration('gen', [], undefined, [ + py.factory.createExpressionStatement( + py.factory.createYieldFromExpression(py.factory.createIdentifier('iterable')), + ), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'from-iterable.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/assignment.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/assignment.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/assignment.test.ts @@ -0,0 +1,13 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('assignment statement', () => { + it('primitive variables', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('foo'), py.factory.createLiteral(42)), + ]); + await assertPrintedMatchesSnapshot(file, 'primitive.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/augmentedAssignment.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/augmentedAssignment.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/augmentedAssignment.test.ts @@ -0,0 +1,92 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('augmented assignment statement', () => { + it('arithmetic operators', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('x'), py.factory.createLiteral(0)), + py.factory.createAssignment(py.factory.createIdentifier('y'), py.factory.createLiteral(0)), + py.factory.createAssignment(py.factory.createIdentifier('z'), py.factory.createLiteral(0)), + py.factory.createAssignment(py.factory.createIdentifier('a'), py.factory.createLiteral(0.0)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(0)), + py.factory.createAssignment(py.factory.createIdentifier('c'), py.factory.createLiteral(0)), + + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('x'), + '+=', + py.factory.createLiteral(1), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('y'), + '-=', + py.factory.createLiteral(2), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('z'), + '*=', + py.factory.createLiteral(3), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('a'), + '/=', + py.factory.createLiteral(4), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('b'), + '//=', + py.factory.createLiteral(5), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('c'), + '%=', + py.factory.createLiteral(6), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'arithmetic.py'); + }); + + it('power and bitwise operators', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('x'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('y'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('z'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('a'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('c'), py.factory.createLiteral(1)), + + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('x'), + '**=', + py.factory.createLiteral(2), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('y'), + '&=', + py.factory.createLiteral(1), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('z'), + '|=', + py.factory.createLiteral(1), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('a'), + '^=', + py.factory.createLiteral(1), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('b'), + '>>=', + py.factory.createLiteral(1), + ), + py.factory.createAugmentedAssignment( + py.factory.createIdentifier('c'), + '<<=', + py.factory.createLiteral(1), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'bitwise.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/block.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/block.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/block.test.ts @@ -0,0 +1,19 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../..'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('block statement', () => { + it('inside function', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('main', [], undefined, [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('inside'), + ]), + ), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'function.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/break.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/break.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/break.test.ts @@ -0,0 +1,15 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('break statement', () => { + it('inside a while loop', async () => { + const file = py.factory.createSourceFile([ + py.factory.createWhileStatement(py.factory.createLiteral(true), [ + py.factory.createBreakStatement(), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'while.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/continue.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/continue.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/continue.test.ts @@ -0,0 +1,15 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('continue statement', () => { + it('inside a while loop', async () => { + const file = py.factory.createSourceFile([ + py.factory.createWhileStatement(py.factory.createLiteral(true), [ + py.factory.createContinueStatement(), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'while.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/expression.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/expression.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/expression.test.ts @@ -0,0 +1,17 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('expression statement', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('hello'), + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'simple.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/for.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/for.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/for.test.ts @@ -0,0 +1,51 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('for statement', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createForStatement( + py.factory.createIdentifier('i'), + py.factory.createCallExpression(py.factory.createIdentifier('range'), [ + py.factory.createLiteral(3), + ]), + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createIdentifier('i'), + ]), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'for.py'); + }); + + it('with else', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('items'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createForStatement( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('items'), + [], + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('done'), + ]), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'for-else.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/if.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/if.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/if.test.ts @@ -0,0 +1,47 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('if statement', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createIfStatement(py.factory.createLiteral(true), [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('positive'), + ]), + ), + ]), + ]); + await assertPrintedMatchesSnapshot(file, 'if.py'); + }); + + it('with else', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('x'), py.factory.createLiteral(0)), + py.factory.createIfStatement( + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '>', + py.factory.createLiteral(0), + ), + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('positive'), + ]), + ), + ], + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('non-positive'), + ]), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'if-else.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/import.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/import.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/import.test.ts @@ -0,0 +1,53 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('import statement', () => { + it('module', async () => { + const file = py.factory.createSourceFile([ + py.factory.createImportStatement('math'), + py.factory.createImportStatement('json', [{ name: 'loads' }], false), + ]); + await assertPrintedMatchesSnapshot(file, 'module.py'); + }); + + it('module with alias', async () => { + const file = py.factory.createSourceFile([ + py.factory.createImportStatement('json', [{ alias: 'js', name: 'json' }], false), + ]); + await assertPrintedMatchesSnapshot(file, 'module-with-alias.py'); + }); + + it('from with name and alias', async () => { + const file = py.factory.createSourceFile([ + py.factory.createImportStatement( + 'os', + [{ name: 'path' }, { alias: 'env', name: 'environ' }], + true, + ), + ]); + await assertPrintedMatchesSnapshot(file, 'from-with-name-alias.py'); + }); + + it('from with alias', async () => { + const file = py.factory.createSourceFile([ + py.factory.createImportStatement('os', [{ alias: 'env', name: 'environ' }], true), + ]); + await assertPrintedMatchesSnapshot(file, 'from-with-alias.py'); + }); + + it('from with name', async () => { + const file = py.factory.createSourceFile([ + py.factory.createImportStatement('sys', [{ name: 'argv' }], true), + ]); + await assertPrintedMatchesSnapshot(file, 'from-with-name.py'); + }); + + it('from with asterisk', async () => { + const file = py.factory.createSourceFile([ + py.factory.createImportStatement('collections', [], true), + ]); + await assertPrintedMatchesSnapshot(file, 'from-with-asterisk.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/raise.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/raise.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/raise.test.ts @@ -0,0 +1,22 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('raise statement', () => { + it('with exception', async () => { + const file = py.factory.createSourceFile([ + py.factory.createRaiseStatement( + py.factory.createCallExpression(py.factory.createIdentifier('ValueError'), [ + py.factory.createLiteral('Invalid input'), + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-exception.py'); + }); + + it('re-raise', async () => { + const file = py.factory.createSourceFile([py.factory.createRaiseStatement()]); + await assertPrintedMatchesSnapshot(file, 'reraise.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/return.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/return.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/return.test.ts @@ -0,0 +1,15 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('return statement', () => { + it('inside function', async () => { + const node = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('get_message', [], undefined, [ + py.factory.createReturnStatement(py.factory.createLiteral('hi')), + ]), + ]); + await assertPrintedMatchesSnapshot(node, 'function.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/try.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/try.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/try.test.ts @@ -0,0 +1,117 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('try statement', () => { + it('with except', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('dangerous_func', [], undefined, []), + py.factory.createEmptyStatement(), + py.factory.createTryStatement( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('dangerous_func'), []), + ), + ], + [ + py.factory.createExceptClause( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createIdentifier('e'), + ]), + ), + ], + py.factory.createIdentifier('ValueError'), + py.factory.createIdentifier('e'), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-except.py'); + }); + + it('with except and else', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('dangerous_func', [], undefined, []), + py.factory.createEmptyStatement(), + py.factory.createTryStatement( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('dangerous_func'), []), + ), + ], + [py.factory.createExceptClause([])], + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-except-else.py'); + }); + + it('with finally', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('dangerous_func', [], undefined, []), + py.factory.createEmptyStatement(), + py.factory.createTryStatement( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('dangerous_func'), []), + ), + ], + undefined, + undefined, + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-finally.py'); + }); + + it('with except and finally', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('dangerous_func', [], undefined, []), + py.factory.createEmptyStatement(), + py.factory.createTryStatement( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('dangerous_func'), []), + ), + ], + [py.factory.createExceptClause([], py.factory.createIdentifier('Exception'))], + undefined, + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-except-finally.py'); + }); + + it('with except, else, and finally', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('dangerous_func', [], undefined, []), + py.factory.createEmptyStatement(), + py.factory.createTryStatement( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('dangerous_func'), []), + ), + ], + [ + py.factory.createExceptClause( + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createIdentifier('e'), + ]), + ), + ], + py.factory.createIdentifier('Exception'), + py.factory.createIdentifier('e'), + ), + ], + [], + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-except-else-finally.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/while.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/while.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/while.test.ts @@ -0,0 +1,55 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('while statement', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('x'), py.factory.createLiteral(3)), + py.factory.createWhileStatement( + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '>', + py.factory.createLiteral(0), + ), + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createIdentifier('x'), + ]), + ), + py.factory.createAssignment( + py.factory.createIdentifier('x'), + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '-', + py.factory.createLiteral(1), + ), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'while.py'); + }); + + it('with else', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration('should_continue', [], undefined, [ + py.factory.createReturnStatement(py.factory.createLiteral(false)), + ]), + py.factory.createWhileStatement( + py.factory.createCallExpression(py.factory.createIdentifier('should_continue'), []), + [], + [ + py.factory.createExpressionStatement( + py.factory.createCallExpression(py.factory.createIdentifier('print'), [ + py.factory.createLiteral('done'), + ]), + ), + ], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'while-else.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/statements/with.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/with.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/statements/with.test.ts @@ -0,0 +1,243 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('with statement', () => { + it('with alias', async () => { + const file = py.factory.createSourceFile([ + py.factory.createClassDeclaration('context_manager', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createWithStatement( + [ + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager'), []), + py.factory.createIdentifier('alias'), + ), + ], + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-alias.py'); + }); + + it('with tuple alias', async () => { + const file = py.factory.createSourceFile([ + py.factory.createClassDeclaration('context_manager', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createWithStatement( + [ + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager'), []), + py.factory.createTupleExpression([ + py.factory.createIdentifier('a'), + py.factory.createIdentifier('b'), + ]), + ), + ], + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-tuple-alias.py'); + }); + + it('without alias', async () => { + const file = py.factory.createSourceFile([ + py.factory.createClassDeclaration('context_manager', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createWithStatement( + [ + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager'), []), + ), + ], + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with.py'); + }); + + it('many with items', async () => { + const file = py.factory.createSourceFile([ + py.factory.createClassDeclaration('context_manager', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createClassDeclaration('context_manager2', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createClassDeclaration('context_manager3', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createWithStatement( + [ + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager'), []), + py.factory.createIdentifier('alias'), + ), + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager2'), []), + py.factory.createTupleExpression([ + py.factory.createIdentifier('a'), + py.factory.createIdentifier('b'), + ]), + ), + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager3'), []), + ), + ], + [], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-many-items.py'); + }); + + it('with async', async () => { + const file = py.factory.createSourceFile([ + py.factory.createClassDeclaration('context_manager', [ + py.factory.createFunctionDeclaration( + '__enter__', + [py.factory.createFunctionParameter('self')], + undefined, + [py.factory.createReturnStatement(py.factory.createIdentifier('self'))], + ), + py.factory.createFunctionDeclaration( + '__exit__', + [ + py.factory.createFunctionParameter('self'), + py.factory.createFunctionParameter('exc_type'), + py.factory.createFunctionParameter('exc_val'), + py.factory.createFunctionParameter('exc_tb'), + ], + undefined, + [py.factory.createReturnStatement(py.factory.createLiteral(false))], + ), + ]), + py.factory.createEmptyStatement(), + py.factory.createFunctionDeclaration( + 'foo', + [], + undefined, + [ + py.factory.createWithStatement( + [ + py.factory.createWithItem( + py.factory.createCallExpression(py.factory.createIdentifier('context_manager'), []), + ), + ], + [], + [py.factory.createIdentifier('async')], + ), + ], + undefined, + undefined, + [py.factory.createIdentifier('async')], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'with-async.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/structure/comment.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/structure/comment.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/structure/comment.test.ts @@ -0,0 +1,11 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('comment', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([py.factory.createComment('This is a comment')]); + await assertPrintedMatchesSnapshot(file, 'simple.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/structure/sourceFile.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/structure/sourceFile.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/structure/sourceFile.test.ts @@ -0,0 +1,27 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../index'; +import { assertPrintedMatchesSnapshot } from '../utils'; + +describe('source file', () => { + it('simple', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment(py.factory.createIdentifier('a'), py.factory.createLiteral(1)), + py.factory.createAssignment(py.factory.createIdentifier('b'), py.factory.createLiteral(2)), + ]); + await assertPrintedMatchesSnapshot(file, 'simple.py'); + }); + + it('with docstring', async () => { + const file = py.factory.createSourceFile( + [ + py.factory.createAssignment( + py.factory.createIdentifier('foo'), + py.factory.createLiteral(1), + ), + ], + 'This is a module-level docstring.', + ); + await assertPrintedMatchesSnapshot(file, 'with-docstring.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/dict.ts b/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/dict.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/dict.ts @@ -0,0 +1,28 @@ +import type { PyComprehensionNode } from '../../comprehension'; +import type { PyExpression } from '../../expression'; +import { PyNodeKind } from '../../kinds'; + +export interface PyDictComprehension extends PyComprehensionNode { + key: PyExpression; + kind: PyNodeKind.DictComprehension; + value: PyExpression; +} + +export function createDictComprehension( + key: PyExpression, + value: PyExpression, + target: PyExpression, + iterable: PyExpression, + ifs?: ReadonlyArray, + isAsync?: boolean, +): PyDictComprehension { + return { + ifs, + isAsync, + iterable, + key, + kind: PyNodeKind.DictComprehension, + target, + value, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/list.ts b/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/list.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/list.ts @@ -0,0 +1,25 @@ +import type { PyComprehensionNode } from '../../comprehension'; +import type { PyExpression } from '../../expression'; +import { PyNodeKind } from '../../kinds'; + +export interface PyListComprehension extends PyComprehensionNode { + element: PyExpression; + kind: PyNodeKind.ListComprehension; +} + +export function createListComprehension( + element: PyExpression, + target: PyExpression, + iterable: PyExpression, + ifs?: ReadonlyArray, + isAsync?: boolean, +): PyListComprehension { + return { + element, + ifs, + isAsync, + iterable, + kind: PyNodeKind.ListComprehension, + target, + }; +} diff --git a/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/set.ts b/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/set.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/nodes/expressions/comprehensions/set.ts @@ -0,0 +1,25 @@ +import type { PyComprehensionNode } from '../../comprehension'; +import type { PyExpression } from '../../expression'; +import { PyNodeKind } from '../../kinds'; + +export interface PySetComprehension extends PyComprehensionNode { + element: PyExpression; + kind: PyNodeKind.SetComprehension; +} + +export function createSetComprehension( + element: PyExpression, + target: PyExpression, + iterable: PyExpression, + ifs?: ReadonlyArray, + isAsync?: boolean, +): PySetComprehension { + return { + element, + ifs, + isAsync, + iterable, + kind: PyNodeKind.SetComprehension, + target, + }; +} diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/default.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/default.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/default.py @@ -0,0 +1,2 @@ +class MyClass: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-decorators.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-decorators.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-decorators.py @@ -0,0 +1,10 @@ +def my_decorator(func): + return func + +def another_decorator(func): + return func + +@my_decorator +@another_decorator +class MyClass: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-docstring.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-docstring.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-docstring.py @@ -0,0 +1,4 @@ +class MyClass: + """This is a class docstring""" + + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-extends.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-extends.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-extends.py @@ -0,0 +1,5 @@ +class BaseClass: + pass + +class MyClass(BaseClass): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-method-docstring.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-method-docstring.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-method-docstring.py @@ -0,0 +1,5 @@ +class MyClass: + def greet(): + """Greets the user.""" + + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-method.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-method.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/class/with-method.py @@ -0,0 +1,3 @@ +class MyClass: + def foo(): + return 42 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/default.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/default.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/default.py @@ -0,0 +1,2 @@ +def greet(): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-annotations-defaults-return.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-annotations-defaults-return.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-annotations-defaults-return.py @@ -0,0 +1,3 @@ +def greet(name: str = "World", times: int = 1) -> None: + for i in range(times): + print("Hello, " + name) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-body.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-body.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-body.py @@ -0,0 +1,2 @@ +def greet(name): + print(name) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-decorators.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-decorators.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-decorators.py @@ -0,0 +1,10 @@ +def my_decorator(func): + return func + +def another_decorator(func): + return func + +@my_decorator +@another_decorator +def greet(): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-docstring.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-docstring.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/declarations/function/with-docstring.py @@ -0,0 +1,4 @@ +def greet(): + """This function prints a greeting.""" + + print("Hello") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/await/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/await/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/await/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/await/inside-function.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/await/inside-function.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/await/inside-function.py @@ -0,0 +1,5 @@ +def fetchData(): + pass + +async def main(): + await fetchData() diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/add.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/add.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/add.py @@ -0,0 +1,3 @@ +a = 42 +b = 84 +z = a + b diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/subtract.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/subtract.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/binary/subtract.py @@ -0,0 +1,3 @@ +a = 42 +b = 84 +z = a - b diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/call/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/call/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/call/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/call/call.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/call/call.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/call/call.py @@ -0,0 +1,1 @@ +print("hi") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/dict/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/dict/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/dict/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/dict/dict.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/dict/dict.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/dict/dict.py @@ -0,0 +1,1 @@ +person = {"name": "Alice", "age": 30} diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/multiple-expressions.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/multiple-expressions.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/multiple-expressions.py @@ -0,0 +1,3 @@ +a = 1 +b = 2 +print(f"Sum: {a + b}") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/simple-interpolation.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/simple-interpolation.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/fString/simple-interpolation.py @@ -0,0 +1,2 @@ +name = "Joe" +print(f"Hello, {name}!") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/async.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/async.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/async.py @@ -0,0 +1,2 @@ +x_iter = [1, 2, 3] +(x async for x in x_iter) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/simple.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/simple.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/simple.py @@ -0,0 +1,2 @@ +x_iter = [1, 2, 3] +(x for x in x_iter) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/with-filter.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/with-filter.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/generator/with-filter.py @@ -0,0 +1,2 @@ +x_iter = [1, 2, 3] +(x for x in x_iter if x > 10) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/identifier/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/identifier/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/identifier/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/identifier/identifier.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/identifier/identifier.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/identifier/identifier.py @@ -0,0 +1,2 @@ +y = 42 +x = y diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/simple.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/simple.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/simple.py @@ -0,0 +1,2 @@ +x = 5 +lambda : x + 1 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/with-params-and-default.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/with-params-and-default.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/lambda/with-params-and-default.py @@ -0,0 +1,1 @@ +lambda x, y = 10: x * y diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/list/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/list/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/list/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/list/list.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/list/list.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/list/list.py @@ -0,0 +1,1 @@ +nums = [1, 2, 3] diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/literal/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/literal/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/literal/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/literal/primitive.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/literal/primitive.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/literal/primitive.py @@ -0,0 +1,4 @@ +s = "hello" +n = 123 +b = True +none = None diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/set/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/set/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/set/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/set/set.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/set/set.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/set/set.py @@ -0,0 +1,4 @@ +foo = "bar" +emptySet = set() +numberSet = {1, 2, 3} +mixedSet = {"a", True, foo} diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/tuple/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/tuple/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/tuple/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/tuple/tuple.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/tuple/tuple.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/tuple/tuple.py @@ -0,0 +1,2 @@ +t = (1, 2, 3) +single = (42,) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/default.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/default.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/default.py @@ -0,0 +1,2 @@ +def gen(): + yield diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/from-iterable.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/from-iterable.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/from-iterable.py @@ -0,0 +1,4 @@ +iterable = [1, 2, 3] + +def gen(): + yield from iterable diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/with-value.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/with-value.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/yield/with-value.py @@ -0,0 +1,2 @@ +def gen(): + yield 42 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/assignment/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/assignment/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/assignment/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/assignment/primitive.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/assignment/primitive.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/assignment/primitive.py @@ -0,0 +1,1 @@ +foo = 42 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/arithmetic.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/arithmetic.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/arithmetic.py @@ -0,0 +1,12 @@ +x = 0 +y = 0 +z = 0 +a = 0 +b = 0 +c = 0 +x += 1 +y -= 2 +z *= 3 +a /= 4 +b //= 5 +c %= 6 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/bitwise.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/bitwise.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/augmentedAssignment/bitwise.py @@ -0,0 +1,12 @@ +x = 1 +y = 1 +z = 1 +a = 1 +b = 1 +c = 1 +x **= 2 +y &= 1 +z |= 1 +a ^= 1 +b >>= 1 +c <<= 1 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/block/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/block/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/block/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/block/function.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/block/function.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/block/function.py @@ -0,0 +1,2 @@ +def main(): + print("inside") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/break/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/break/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/break/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/break/while.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/break/while.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/break/while.py @@ -0,0 +1,2 @@ +while True: + break diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/continue/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/continue/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/continue/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/continue/while.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/continue/while.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/continue/while.py @@ -0,0 +1,2 @@ +while True: + continue diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/expression/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/expression/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/expression/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/expression/simple.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/expression/simple.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/expression/simple.py @@ -0,0 +1,1 @@ +print("hello") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/for-else.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/for-else.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/for-else.py @@ -0,0 +1,5 @@ +items = [1, 2, 3] +for x in items: + pass +else: + print("done") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/for.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/for.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/for/for.py @@ -0,0 +1,2 @@ +for i in range(3): + print(i) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/if-else.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/if-else.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/if-else.py @@ -0,0 +1,5 @@ +x = 0 +if x > 0: + print("positive") +else: + print("non-positive") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/if.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/if.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/if/if.py @@ -0,0 +1,2 @@ +if True: + print("positive") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-alias.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-alias.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-alias.py @@ -0,0 +1,1 @@ +from os import environ as env diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-asterisk.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-asterisk.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-asterisk.py @@ -0,0 +1,1 @@ +from collections import * diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-name-alias.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-name-alias.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-name-alias.py @@ -0,0 +1,1 @@ +from os import path, environ as env diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-name.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-name.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/from-with-name.py @@ -0,0 +1,1 @@ +from sys import argv diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/module-with-alias.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/module-with-alias.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/module-with-alias.py @@ -0,0 +1,1 @@ +import json as js diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/module.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/module.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/import/module.py @@ -0,0 +1,2 @@ +import math +import loads diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/reraise.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/reraise.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/reraise.py @@ -0,0 +1,1 @@ +raise diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/with-exception.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/with-exception.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/raise/with-exception.py @@ -0,0 +1,1 @@ +raise ValueError("Invalid input") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/return/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/return/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/return/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/return/function.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/return/function.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/return/function.py @@ -0,0 +1,2 @@ +def get_message(): + return "hi" diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-else-finally.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-else-finally.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-else-finally.py @@ -0,0 +1,11 @@ +def dangerous_func(): + pass + +try: + dangerous_func() +except Exception as e: + print(e) +else: + pass +finally: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-else.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-else.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-else.py @@ -0,0 +1,9 @@ +def dangerous_func(): + pass + +try: + dangerous_func() +except: + pass +else: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-finally.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-finally.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except-finally.py @@ -0,0 +1,9 @@ +def dangerous_func(): + pass + +try: + dangerous_func() +except Exception: + pass +finally: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-except.py @@ -0,0 +1,7 @@ +def dangerous_func(): + pass + +try: + dangerous_func() +except ValueError as e: + print(e) diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-finally.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-finally.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/try/with-finally.py @@ -0,0 +1,7 @@ +def dangerous_func(): + pass + +try: + dangerous_func() +finally: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/while-else.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/while-else.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/while-else.py @@ -0,0 +1,6 @@ +def should_continue(): + return False +while should_continue(): + pass +else: + print("done") diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/while.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/while.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/while/while.py @@ -0,0 +1,4 @@ +x = 3 +while x > 0: + print(x) + x = x - 1 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-alias.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-alias.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-alias.py @@ -0,0 +1,8 @@ +class context_manager: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +with context_manager() as alias: + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-async.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-async.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-async.py @@ -0,0 +1,9 @@ +class context_manager: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +async def foo(): + async with context_manager(): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-many-items.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-many-items.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-many-items.py @@ -0,0 +1,20 @@ +class context_manager: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +class context_manager2: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +class context_manager3: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +with context_manager() as alias, context_manager2() as (a, b), context_manager3(): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-tuple-alias.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-tuple-alias.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with-tuple-alias.py @@ -0,0 +1,8 @@ +class context_manager: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +with context_manager() as (a, b): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/statements/with/with.py @@ -0,0 +1,8 @@ +class context_manager: + def __enter__(self): + return self + def __exit__(self, exc_type, exc_val, exc_tb): + return False + +with context_manager(): + pass diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/comment/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/comment/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/comment/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/comment/simple.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/comment/simple.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/comment/simple.py @@ -0,0 +1,1 @@ +# This is a comment diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/simple.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/simple.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/simple.py @@ -0,0 +1,2 @@ +a = 1 +b = 2 diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/with-docstring.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/with-docstring.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/structure/sourceFile/with-docstring.py @@ -0,0 +1,3 @@ +"""This is a module-level docstring.""" + +foo = 1 diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/dict.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/dict.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/dict.test.ts @@ -0,0 +1,60 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../../index'; +import { assertPrintedMatchesSnapshot } from '../../utils'; + +describe('dict comprehension', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'foo', + [], + undefined, + [ + py.factory.createAssignment( + py.factory.createIdentifier('items'), + py.factory.createDictExpression([ + { + key: py.factory.createLiteral('key1'), + value: py.factory.createLiteral('value1'), + }, + { + key: py.factory.createLiteral('key2'), + value: py.factory.createLiteral('value2'), + }, + ]), + ), + py.factory.createExpressionStatement( + py.factory.createDictComprehension( + py.factory.createIdentifier('k'), + py.factory.createIdentifier('v'), + py.factory.createTupleExpression([ + py.factory.createIdentifier('k'), + py.factory.createIdentifier('v'), + ]), + py.factory.createCallExpression( + py.factory.createMemberExpression( + py.factory.createIdentifier('items'), + py.factory.createIdentifier('items'), + ), + [], + ), + [ + py.factory.createBinaryExpression( + py.factory.createIdentifier('k'), + '%', + py.factory.createLiteral(2), + ), + ], + true, + ), + ), + ], + undefined, + undefined, + [py.factory.createIdentifier('async')], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'dict.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/list.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/list.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/list.test.ts @@ -0,0 +1,50 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../../index'; +import { assertPrintedMatchesSnapshot } from '../../utils'; + +describe('list comprehension', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'foo', + [], + undefined, + [ + py.factory.createAssignment( + py.factory.createIdentifier('items'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createAssignment( + py.factory.createIdentifier('evens'), + py.factory.createListComprehension( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x'), + py.factory.createIdentifier('items'), + [ + py.factory.createBinaryExpression( + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '%', + py.factory.createLiteral(2), + ), + '==', + py.factory.createLiteral(0), + ), + ], + true, + ), + ), + ], + undefined, + undefined, + [py.factory.createIdentifier('async')], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'list.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/nested.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/nested.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/nested.test.ts @@ -0,0 +1,34 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../../index'; +import { assertPrintedMatchesSnapshot } from '../../utils'; + +describe('nested comprehension', () => { + it('dict and list', async () => { + const file = py.factory.createSourceFile([ + py.factory.createAssignment( + py.factory.createIdentifier('data'), + py.factory.createDictExpression([ + { + key: py.factory.createLiteral('numbers'), + value: py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + }, + { + key: py.factory.createLiteral('nestedDict'), + value: py.factory.createDictExpression([ + { + key: py.factory.createLiteral('foo'), + value: py.factory.createLiteral('bar'), + }, + ]), + }, + ]), + ), + ]); + await assertPrintedMatchesSnapshot(file, 'dict-list.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/set.test.ts b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/set.test.ts new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__tests__/nodes/expressions/comprehensions/set.test.ts @@ -0,0 +1,45 @@ +import { describe, it } from 'vitest'; + +import { py } from '../../../../index'; +import { assertPrintedMatchesSnapshot } from '../../utils'; + +describe('set comprehension', () => { + it('assignment', async () => { + const file = py.factory.createSourceFile([ + py.factory.createFunctionDeclaration( + 'foo', + [], + undefined, + [ + py.factory.createAssignment( + py.factory.createIdentifier('items'), + py.factory.createListExpression([ + py.factory.createLiteral(1), + py.factory.createLiteral(2), + py.factory.createLiteral(3), + ]), + ), + py.factory.createAssignment( + py.factory.createIdentifier('unique_evens'), + py.factory.createSetComprehension( + py.factory.createIdentifier('x'), + py.factory.createIdentifier('x'), + py.factory.createIdentifier('items'), + [ + py.factory.createBinaryExpression( + py.factory.createIdentifier('x'), + '%', + py.factory.createLiteral(2), + ), + ], + ), + ), + ], + undefined, + undefined, + [py.factory.createIdentifier('async')], + ), + ]); + await assertPrintedMatchesSnapshot(file, 'dict.py'); + }); +}); diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/dict/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/dict/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/dict/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/dict/dict.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/dict/dict.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/dict/dict.py @@ -0,0 +1,3 @@ +async def foo(): + items = {"key1": "value1", "key2": "value2"} + {k: v async for (k, v) in items.items() if k % 2} diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/list/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/list/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/list/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/list/list.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/list/list.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/list/list.py @@ -0,0 +1,3 @@ +async def foo(): + items = [1, 2, 3] + evens = [x async for x in items if x % 2 == 0] diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/nested/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/nested/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/nested/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/nested/dict-list.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/nested/dict-list.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/nested/dict-list.py @@ -0,0 +1,1 @@ +data = {"numbers": [1, 2, 3], "nestedDict": {"foo": "bar"}} diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/set/__init__.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/set/__init__.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/set/__init__.py diff --git a/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/set/dict.py b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/set/dict.py new file mode 100644 --- /dev/null +++ b/packages/openapi-python/src/ts-python/__snapshots__/nodes/expressions/comprehensions/set/dict.py @@ -0,0 +1,3 @@ +async def foo(): + items = [1, 2, 3] + unique_evens = {x for x in items if x % 2}