diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 22a1e27e4..e87690c0d 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -12,10 +12,10 @@ jobs: steps: - name: Check out Git repository uses: actions/checkout@v4 - - name: Set up Python 3.10 + - name: Set up Python 3.11 uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.11" - name: Install pip deps run: | diff --git a/.github/workflows/pre-release-robocorp-code.yml b/.github/workflows/pre-release-sema4ai-sdk.yml similarity index 98% rename from .github/workflows/pre-release-robocorp-code.yml rename to .github/workflows/pre-release-sema4ai-sdk.yml index da08cb83e..bc5c5bd0f 100644 --- a/.github/workflows/pre-release-robocorp-code.yml +++ b/.github/workflows/pre-release-sema4ai-sdk.yml @@ -28,10 +28,10 @@ jobs: - name: Yarn install run: yarn install - - name: Set up Python 3.10 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - name: Install deps run: pip install --upgrade pip fire poetry diff --git a/.github/workflows/release-robocorp-code-vscode.yml b/.github/workflows/release-sema4ai-sdk.yml similarity index 98% rename from .github/workflows/release-robocorp-code-vscode.yml rename to .github/workflows/release-sema4ai-sdk.yml index 41a306362..3eaf40110 100644 --- a/.github/workflows/release-robocorp-code-vscode.yml +++ b/.github/workflows/release-sema4ai-sdk.yml @@ -21,10 +21,10 @@ jobs: node-version: 20.x - name: Yarn install run: yarn install - - name: Set up Python 3.10 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - name: Install deps run: pip install --upgrade pip fire poetry - name: Vendor sema4ai_ls_core diff --git a/.github/workflows/tests-robocorp-python-ls-core.yml b/.github/workflows/tests-robocorp-python-ls-core.yml deleted file mode 100644 index ddb8664b8..000000000 --- a/.github/workflows/tests-robocorp-python-ls-core.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Tests - Python Language Server Core (sema4ai-python-ls-core) - -on: - push: - paths: - - sema4ai-python-ls-core/** - - .github/** - - - pull_request: - paths: - - sema4ai-python-ls-core/** - - .github/** - -jobs: - build: - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - name: [ - "windows-py310", - "ubuntu-py310", - "macos-py310" - ] - - include: - - name: "windows-py310" - python: "3.10" - os: windows-latest - - name: "ubuntu-py310" - python: "3.10" - os: ubuntu-latest - - name: "macos-py310" - python: "3.10" - os: macos-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - name: Upgrade pip, install fire, poetry - run: | - python -m pip install --upgrade pip - pip install fire poetry - - name: poetry install - working-directory: ./sema4ai-python-ls-core - run: | - poetry install - - name: Test - working-directory: ./sema4ai-python-ls-core/tests - env: - PYTHONPATH: . - run: poetry run python -u ./run_tests.py -rfE -otests_output -vv . - - uses: actions/upload-artifact@v4 - with: - name: tests_output.${{ matrix.name }}.txt - path: sema4ai-python-ls-core/tests/tests_output - diff --git a/.github/workflows/tests-sema4ai-python-ls-core.yml b/.github/workflows/tests-sema4ai-python-ls-core.yml new file mode 100644 index 000000000..f150d1998 --- /dev/null +++ b/.github/workflows/tests-sema4ai-python-ls-core.yml @@ -0,0 +1,57 @@ +name: Tests - Python Language Server Core (sema4ai-python-ls-core) + +on: + push: + paths: + - sema4ai-python-ls-core/** + - .github/** + + pull_request: + paths: + - sema4ai-python-ls-core/** + - .github/** + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + name: ["windows-py311", "ubuntu-py311", "macos-py311"] + + include: + - name: "windows-py311" + python: "3.11" + os: windows-latest + - name: "ubuntu-py311" + python: "3.11" + os: ubuntu-latest + - name: "macos-py311" + python: "3.11" + os: macos-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + - name: Upgrade pip, install fire, poetry + run: | + python -m pip install --upgrade pip + pip install fire poetry + - name: poetry install + working-directory: ./sema4ai-python-ls-core + run: | + poetry install + - name: Test + working-directory: ./sema4ai-python-ls-core/tests + env: + PYTHONPATH: . + run: poetry run python -u ./run_tests.py -rfE -otests_output -vv . + - uses: actions/upload-artifact@v4 + with: + name: tests_output.${{ matrix.name }}.txt + path: sema4ai-python-ls-core/tests/tests_output diff --git a/.github/workflows/tests-sema4ai-sdk-data-server-integration.yml b/.github/workflows/tests-sema4ai-sdk-data-server-integration.yml new file mode 100644 index 000000000..0a3a0cbe0 --- /dev/null +++ b/.github/workflows/tests-sema4ai-sdk-data-server-integration.yml @@ -0,0 +1,84 @@ +name: Tests - Sema4.ai Data Server Integration (sema4ai) + +on: + push: + paths: + - sema4ai/** + - sema4ai-python-ls-core/** + - .github/** + + pull_request: + paths: + - sema4ai/** + - sema4ai-python-ls-core/** + - .github/** + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + name: [ + "ubuntu-py311", + "windows-py311", +# "mac-py311", mac disabled because it takes too long for runners to pick the mac job up. + ] + + include: + - name: "ubuntu-py311" + python: "3.11" + os: ubuntu-latest + - name: "windows-py311" + python: "3.11" + os: windows-latest +# - name: "mac-py311" +# python: "3.11" +# os: mac-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + - name: Upgrade pip + run: python -m pip install --upgrade pip + - name: Vendor sema4ai_ls_core + working-directory: ./sema4ai + run: | + pip install fire poetry + python -m dev vendor-robocorp-ls-core + - name: poetry install + working-directory: ./sema4ai + run: poetry install + - name: Run codegen + run: python -m dev codegen + working-directory: ./sema4ai + env: + PYTHONPATH: src + - name: Test + working-directory: ./sema4ai/tests + env: + PYTHONPATH: . + CI_CREDENTIALS: ${{ secrets.CI_CREDENTIALS }} + CI_ENDPOINT: ${{ secrets.CI_ENDPOINT }} + # Big timeout to create environment in windows. + RUN_TESTS_TIMEOUT: 3000 + ACTION_SERVER_TEST_ACCESS_CREDENTIALS: ${{ secrets.ACTION_SERVER_TEST_ACCESS_CREDENTIALS }} + + run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -otests_output_data_server -vv -m data_server . + + - uses: actions/upload-artifact@v4 + if: always() + with: + name: tests_output_data_server.${{ matrix.name }}.txt + path: sema4ai/tests/tests_output_data_server + - uses: actions/upload-artifact@v4 + if: always() + with: + name: log_data_server.${{ matrix.name }}.html + path: sema4ai/tests/output/log.html + diff --git a/.github/workflows/tests-robocorp-code-vscode.yml b/.github/workflows/tests-sema4ai-sdk.yml similarity index 83% rename from .github/workflows/tests-robocorp-code-vscode.yml rename to .github/workflows/tests-sema4ai-sdk.yml index 6c2b43adb..e40a08ba3 100644 --- a/.github/workflows/tests-robocorp-code-vscode.yml +++ b/.github/workflows/tests-sema4ai-sdk.yml @@ -21,20 +21,20 @@ jobs: fail-fast: false matrix: name: [ - "ubuntu-py310", - "windows-py310", -# "mac-py310", mac disabled because it takes too long for runners to pick the mac job up. + "ubuntu-py311", + "windows-py311", +# "mac-py311", mac disabled because it takes too long for runners to pick the mac job up. ] include: - - name: "ubuntu-py310" - python: "3.10" + - name: "ubuntu-py311" + python: "3.11" os: ubuntu-latest - - name: "windows-py310" - python: "3.10" + - name: "windows-py311" + python: "3.11" os: windows-latest -# - name: "mac-py310" -# python: "3.10" +# - name: "mac-py311" +# python: "3.11" # os: mac-latest steps: @@ -69,7 +69,8 @@ jobs: RUN_TESTS_TIMEOUT: 3000 ACTION_SERVER_TEST_ACCESS_CREDENTIALS: ${{ secrets.ACTION_SERVER_TEST_ACCESS_CREDENTIALS }} - run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -otests_output -vv . + run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -otests_output -vv -m "not data_server" . + - uses: actions/upload-artifact@v4 if: always() with: diff --git a/docs/changelog.md b/docs/changelog.md index 7690b7f6e..71742b66f 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -8,11 +8,13 @@ - New icons for the extension. - Aligned the release details for the extension - Update Agent CLI to `0.2.2` -- Add `Start Data Server` and `Stop Data Server` commands - Search for actions/queries/predictions considering all glob patterns supported by `sema4ai.actions`. - Use `package.yaml` directory as the `cwd` when searching for actions/queries/predictions if available (otherwise imports could fail). - Show progress when creating the input file for an action/query/prediction. - Integrate with the VSCode Sema4.ai Data Extension to get the data server info to run data actions. +- No longer use `robocorp-trustore` (it's no longer needed). +- Use `sema4ai-http-helper` to make http requests (to data server). +- Use `Python 3.11` as the base interpreter. ## New in 2.8.1 (2024-11-21) diff --git a/sema4ai-python-ls-core/poetry.lock b/sema4ai-python-ls-core/poetry.lock index aa60f6865..65e06533c 100644 --- a/sema4ai-python-ls-core/poetry.lock +++ b/sema4ai-python-ls-core/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "colorama" @@ -11,20 +11,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "execnet" version = "2.1.1" @@ -41,16 +27,15 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "fire" -version = "0.6.0" +version = "0.7.0" description = "A library for automatically generating command line interfaces." optional = false python-versions = "*" files = [ - {file = "fire-0.6.0.tar.gz", hash = "sha256:54ec5b996ecdd3c0309c800324a0703d6da512241bc73b553db959d98de0aa66"}, + {file = "fire-0.7.0.tar.gz", hash = "sha256:961550f07936eaf65ad1dc8360f2b2bf8408fad46abbfa4d2a3794f8d2a95cdf"}, ] [package.dependencies] -six = "*" termcolor = "*" [[package]] @@ -107,47 +92,52 @@ test = ["pytest", "pytest-cov"] [[package]] name = "mypy" -version = "1.11.2" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, - {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, - {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, - {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, - {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, - {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, - {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, - {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, - {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, - {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, - {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, - {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, - {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, - {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, - {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, - {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, - {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, - {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, - {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -165,13 +155,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -219,22 +209,20 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -371,18 +359,17 @@ files = [ [[package]] name = "robocorp-log" -version = "2.9.2" +version = "2.9.3" description = "Automatic trace logging for Python" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "robocorp_log-2.9.2-py3-none-any.whl", hash = "sha256:e4efdf9a7fc8f949be3fafc24016943a7449e113fc30ca40807ab9b0e54dba68"}, - {file = "robocorp_log-2.9.2.tar.gz", hash = "sha256:8917057b2eb5fc6713ff4aa255b43cce809bdc6a59ab637630b8444fe4bba0a6"}, + {file = "robocorp_log-2.9.3-py3-none-any.whl", hash = "sha256:ef365b5c67c392835cd1af10f898e4ed37b7058e075dc7957bf0cd44653d7100"}, + {file = "robocorp_log-2.9.3.tar.gz", hash = "sha256:ecde32a50489af16a9f4941452d729298d809fcf212772559c93965854cdef17"}, ] [package.dependencies] psutil = ">=5.9,<6.0" -tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} [[package]] name = "robocorp-log-pytest" @@ -399,17 +386,6 @@ files = [ pytest = ">=7" robocorp-log = ">=2.5,<3" -[[package]] -name = "robocorp-truststore" -version = "0.9.1" -description = "Verify certificates using native system trust stores" -optional = false -python-versions = ">=3.10" -files = [ - {file = "robocorp_truststore-0.9.1-py3-none-any.whl", hash = "sha256:dfdd4812dffce8a91134e8b69a3c55072fc9785dbdd583d4047f323779ac2f39"}, - {file = "robocorp_truststore-0.9.1.tar.gz", hash = "sha256:a1abfd9c5b7fe22152a8eeb9510812800dca741851c720742c598c0f78ee4f3f"}, -] - [[package]] name = "ruff" version = "0.1.15" @@ -460,29 +436,18 @@ files = [ [[package]] name = "termcolor" -version = "2.4.0" +version = "2.5.0" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, + {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, + {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, ] [package.extras] tests = ["pytest", "pytest-cov"] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "tomlkit" version = "0.11.8" @@ -496,13 +461,13 @@ files = [ [[package]] name = "types-docutils" -version = "0.21.0.20240724" +version = "0.21.0.20241128" description = "Typing stubs for docutils" optional = false python-versions = ">=3.8" files = [ - {file = "types-docutils-0.21.0.20240724.tar.gz", hash = "sha256:29ff7e27660f4fe76ea61d7e54d05ca3ce3b733ca9e8e8721e0fa587dbc10489"}, - {file = "types_docutils-0.21.0.20240724-py3-none-any.whl", hash = "sha256:bf51c6c488d23c0412f9b3ba10686fb1a6cb0b957ef04b45128d8a55c79ebb00"}, + {file = "types_docutils-0.21.0.20241128-py3-none-any.whl", hash = "sha256:e0409204009639e9b0bf4521eeabe58b5e574ce9c0db08421c2ac26c32be0039"}, + {file = "types_docutils-0.21.0.20241128.tar.gz", hash = "sha256:4dd059805b83ac6ec5a223699195c4e9eeb0446a4f7f2aeff1759a4a7cc17473"}, ] [[package]] @@ -562,13 +527,13 @@ files = [ [[package]] name = "types-pyyaml" -version = "6.0.12.20240808" +version = "6.0.12.20240917" description = "Typing stubs for PyYAML" optional = false python-versions = ">=3.8" files = [ - {file = "types-PyYAML-6.0.12.20240808.tar.gz", hash = "sha256:b8f76ddbd7f65440a8bda5526a9607e4c7a322dc2f8e1a8c405644f9a6f4b9af"}, - {file = "types_PyYAML-6.0.12.20240808-py3-none-any.whl", hash = "sha256:deda34c5c655265fc517b546c902aa6eed2ef8d3e921e4765fe606fe2afe8d35"}, + {file = "types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587"}, + {file = "types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570"}, ] [[package]] @@ -584,5 +549,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = ">=3.10,<3.11" -content-hash = "4b015d2c3b9c80ba4fedd5de81b685d4943b8b693717da9c1c96b9a7a4a0ebf4" +python-versions = ">=3.11,<3.12" +content-hash = "4627aa7642579b28dcb4c9fddb65ddaf9a88945b45b43fe71a1f9e71a80d3349" diff --git a/sema4ai-python-ls-core/pyproject.toml b/sema4ai-python-ls-core/pyproject.toml index b526e77ad..f883fcca8 100644 --- a/sema4ai-python-ls-core/pyproject.toml +++ b/sema4ai-python-ls-core/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ ] [tool.poetry.dependencies] -python = ">=3.10,<3.11" +python = ">=3.11,<3.12" tomli = { version = "^2.0.1", python = "<3.11" } [tool.poetry.group.dev.dependencies] @@ -43,7 +43,6 @@ isort = { version = "^5.12.0", python = "^3.8" } invoke = "^2.0" tomlkit = "^0.11.8" semver = "^3.0.0" -robocorp-truststore = "0.9.1" mock = "*" pytest = "*" diff --git a/sema4ai-python-ls-core/src/sema4ai_ls_core/protocols.py b/sema4ai-python-ls-core/src/sema4ai_ls_core/protocols.py index 74ecf9cbe..9840eb464 100644 --- a/sema4ai-python-ls-core/src/sema4ai_ls_core/protocols.py +++ b/sema4ai-python-ls-core/src/sema4ai_ls_core/protocols.py @@ -3,7 +3,18 @@ import typing from collections.abc import Callable, Iterable, Mapping from enum import Enum -from typing import Any, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union +from typing import ( + Any, + Dict, + Generic, + List, + Literal, + Optional, + Tuple, + Type, + TypeVar, + Union, +) if typing.TYPE_CHECKING: # This would lead to a circular import, so, do it only when type-checking. @@ -13,6 +24,7 @@ CompletionItemTypedDict, CompletionResolveResponseTypedDict, CompletionsResponseTypedDict, + DiagnosticsTypedDict, DocumentHighlightResponseTypedDict, HoverResponseTypedDict, PositionTypedDict, @@ -904,12 +916,12 @@ def add_listener(self, listener: IMonitorListener): """ -class ActionResultDict(TypedDict): +class ActionResultDict(TypedDict, Generic[T]): success: bool message: None | ( str ) # if success == False, this can be some message to show to the user - result: Any + result: T | None class ActionResult(Generic[T]): @@ -926,7 +938,7 @@ def __init__( self.message = message self.result = result - def as_dict(self) -> ActionResultDict: + def as_dict(self) -> ActionResultDict[T]: return {"success": self.success, "message": self.message, "result": self.result} def __str__(self): @@ -977,3 +989,28 @@ class LibraryVersionInfoDict(TypedDict): # Note that if the library was found but the version doesn't match, the # result should still be provided. result: LibraryVersionDict | None + + +class ActionInfoTypedDict(TypedDict): + range: "RangeTypedDict" + name: str + uri: str + kind: str + + +class DatasourceInfoTypedDict(TypedDict): + python_variable_name: str | None + range: "RangeTypedDict" + name: str + uri: str + kind: Literal["datasource"] + engine: str + model_name: str | None + created_table: str | None + + +class DataSourceStateDict(TypedDict): + unconfigured_data_sources: list[DatasourceInfoTypedDict] + uri_to_error_messages: dict[str, list["DiagnosticsTypedDict"]] + required_data_sources: list[DatasourceInfoTypedDict] + data_sources_in_data_server: list[str] diff --git a/sema4ai/bin/create_env/conda.yaml b/sema4ai/bin/create_env/conda.yaml index 3d370c103..ed6399aea 100644 --- a/sema4ai/bin/create_env/conda.yaml +++ b/sema4ai/bin/create_env/conda.yaml @@ -4,14 +4,14 @@ channels: - conda-forge dependencies: - - python=3.10.12 # https://pyreadiness.org/3.10/ - - uv=0.2.37 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md + - python=3.11.10 # https://pyreadiness.org/3.11/ + - uv=0.4.17 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md - pyyaml=6.0.1 - ruamel.yaml=0.18.6 - msgspec=0.18.2 - pip: - - robocorp-truststore==0.9.1 # https://github.com/sethmlarson/truststore/blob/main/CHANGELOG.md - robocorp-inspector==0.10.2 # https://github.com/robocorp/inspector/blob/master/CHANGELOG.md - playwright==1.37.0 - tree-sitter==0.22.3 - tree-sitter-yaml==0.6.0 + - sema4ai-http-helper==1.0.2 diff --git a/sema4ai/bin/create_env/conda_vscode_darwin_amd64.yaml b/sema4ai/bin/create_env/conda_vscode_darwin_amd64.yaml index 2a5cb24de..f16ecbe02 100644 --- a/sema4ai/bin/create_env/conda_vscode_darwin_amd64.yaml +++ b/sema4ai/bin/create_env/conda_vscode_darwin_amd64.yaml @@ -4,16 +4,16 @@ channels: - conda-forge dependencies: - - python=3.10.12 # https://pyreadiness.org/3.10/ - - uv=0.2.37 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md + - python=3.11.10 # https://pyreadiness.org/3.11/ + - uv=0.4.17 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md - pyyaml=6.0.1 - ruamel.yaml=0.18.6 - msgspec=0.18.2 - - python.app=1.3 # https://anaconda.org/conda-forge/python.app/files + - python.app=1.4 # https://anaconda.org/conda-forge/python.app/files - pyscreeze==0.1.30 # VSCode Image Inspector dependency - python-mss==9.0.1 # VSCode Image Inspector dependency - pip: - - robocorp-truststore==0.9.1 # https://github.com/sethmlarson/truststore/blob/main/CHANGELOG.md - playwright==1.37.0 - tree-sitter==0.22.3 - tree-sitter-yaml==0.6.0 + - sema4ai-http-helper==1.0.2 diff --git a/sema4ai/bin/create_env/conda_vscode_linux_amd64.yaml b/sema4ai/bin/create_env/conda_vscode_linux_amd64.yaml index fd70ac422..ad49cdab1 100644 --- a/sema4ai/bin/create_env/conda_vscode_linux_amd64.yaml +++ b/sema4ai/bin/create_env/conda_vscode_linux_amd64.yaml @@ -4,15 +4,15 @@ channels: - conda-forge dependencies: - - python=3.10.12 # https://pyreadiness.org/3.10/ - - uv=0.2.37 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md + - python=3.11.10 # https://pyreadiness.org/3.11/ + - uv=0.4.17 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md - pyyaml=6.0.1 - ruamel.yaml=0.18.6 - msgspec=0.18.2 - pyscreeze==0.1.30 # VSCode Image Inspector dependency - python-mss==9.0.1 # VSCode Image Inspector dependency - pip: - - robocorp-truststore==0.9.1 # https://github.com/sethmlarson/truststore/blob/main/CHANGELOG.md - playwright==1.37.0 - tree-sitter==0.22.3 - tree-sitter-yaml==0.6.0 + - sema4ai-http-helper==1.0.2 diff --git a/sema4ai/bin/create_env/conda_vscode_windows_amd64.yaml b/sema4ai/bin/create_env/conda_vscode_windows_amd64.yaml index 7fcde6995..0fb2f7310 100644 --- a/sema4ai/bin/create_env/conda_vscode_windows_amd64.yaml +++ b/sema4ai/bin/create_env/conda_vscode_windows_amd64.yaml @@ -4,8 +4,8 @@ channels: - conda-forge dependencies: - - python=3.10.12 # https://pyreadiness.org/3.10/ - - uv=0.2.37 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md + - python=3.11.10 # https://pyreadiness.org/3.10/ + - uv=0.4.17 # https://github.com/astral-sh/uv/blob/main/CHANGELOG.md - pyyaml=6.0.1 - ruamel.yaml=0.18.6 - msgspec=0.18.2 @@ -16,7 +16,7 @@ dependencies: - psutil==5.9.8 # VSCode Windows Inspector dependency - java-access-bridge-wrapper==1.2.0 # VSCode Java Inspector dependency - pip: - - robocorp-truststore==0.9.1 # https://github.com/sethmlarson/truststore/blob/main/CHANGELOG.md - playwright==1.37.0 - tree-sitter==0.22.3 - tree-sitter-yaml==0.6.0 + - sema4ai-http-helper==1.0.2 diff --git a/sema4ai/codegen/commands.py b/sema4ai/codegen/commands.py index 31b2677b2..d9dcaea22 100644 --- a/sema4ai/codegen/commands.py +++ b/sema4ai/codegen/commands.py @@ -1019,18 +1019,6 @@ def __init__( server_handled=False, hide_from_command_palette=True, ), - Command( - "sema4ai.startDataServer", - "Start Data Server", - server_handled=False, - add_to_package_json=True, - ), - Command( - "sema4ai.stopDataServer", - "Stop Data Server", - server_handled=False, - add_to_package_json=True, - ), ] diff --git a/sema4ai/package.json b/sema4ai/package.json index 448bde4b0..1f58492a5 100644 --- a/sema4ai/package.json +++ b/sema4ai/package.json @@ -174,8 +174,6 @@ "onCommand:sema4ai.importActionPackage", "onCommand:sema4ai.runActionPackageDevTask", "onCommand:sema4ai.getActionsMetadata", - "onCommand:sema4ai.startDataServer", - "onCommand:sema4ai.stopDataServer", "onDebugInitialConfigurations", "onDebugResolve:sema4ai", "onView:sema4ai-task-packages-tree", @@ -1008,16 +1006,6 @@ "command": "sema4ai.getActionsMetadata", "title": "Get Actions Metadata", "category": "Sema4.ai" - }, - { - "command": "sema4ai.startDataServer", - "title": "Start Data Server", - "category": "Sema4.ai" - }, - { - "command": "sema4ai.stopDataServer", - "title": "Stop Data Server", - "category": "Sema4.ai" } ], "menus": { diff --git a/sema4ai/poetry.lock b/sema4ai/poetry.lock index 25a4eccbe..783b8e960 100644 --- a/sema4ai/poetry.lock +++ b/sema4ai/poetry.lock @@ -103,49 +103,49 @@ files = [ [[package]] name = "comtypes" -version = "1.4.7" +version = "1.4.8" description = "Pure Python COM package" optional = false python-versions = ">=3.8" files = [ - {file = "comtypes-1.4.7-py3-none-any.whl", hash = "sha256:d46ac2bfb6176eda6b03cd64b9afaa212224ede105054e77aac6bbbd8d9979db"}, - {file = "comtypes-1.4.7.zip", hash = "sha256:cc4f3cd5db28c6a0c9fce781720192c60b2f198e548fd6dfcfc1d47b6f8ea20f"}, + {file = "comtypes-1.4.8-py3-none-any.whl", hash = "sha256:773109b12aa0bec630d5b2272dd983cbaa25605a12fc1319f99730c9d0b72f79"}, + {file = "comtypes-1.4.8.zip", hash = "sha256:bb2286cfb3b96f838307200a85b00b98e1bdebf1e58ec3c28b36b1ccfafac01f"}, ] [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] @@ -158,7 +158,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -172,20 +172,6 @@ files = [ {file = "docstring_parser_fork-0.0.5.tar.gz", hash = "sha256:395ae8ee6a359e268670ebc4fe9a40dab917a94f6decd7cda8e86f9bea5c9456"}, ] -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "execnet" version = "2.1.1" @@ -202,83 +188,97 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "fire" -version = "0.6.0" +version = "0.7.0" description = "A library for automatically generating command line interfaces." optional = false python-versions = "*" files = [ - {file = "fire-0.6.0.tar.gz", hash = "sha256:54ec5b996ecdd3c0309c800324a0703d6da512241bc73b553db959d98de0aa66"}, + {file = "fire-0.7.0.tar.gz", hash = "sha256:961550f07936eaf65ad1dc8360f2b2bf8408fad46abbfa4d2a3794f8d2a95cdf"}, ] [package.dependencies] -six = "*" termcolor = "*" [[package]] name = "greenlet" -version = "3.0.3" +version = "3.1.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, ] [package.extras] @@ -420,47 +420,52 @@ test = ["numpy (==2.1.0)", "pillow (==10.4.0)", "pytest (==8.3.2)", "pytest-cov [[package]] name = "mypy" -version = "1.11.2" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, - {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, - {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, - {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, - {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, - {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, - {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, - {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, - {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, - {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, - {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, - {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, - {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, - {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, - {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, - {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, - {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, - {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, - {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -523,13 +528,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -584,7 +589,7 @@ files = [ ] [package.dependencies] -numpy = {version = ">=1.22.4", markers = "python_version < \"3.11\""} +numpy = {version = ">=1.23.2", markers = "python_version == \"3.11\""} python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.7" @@ -713,22 +718,22 @@ xmp = ["defusedxml"] [[package]] name = "playwright" -version = "1.47.0" +version = "1.49.0" description = "A high-level API to automate web browsers" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "playwright-1.47.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:f205df24edb925db1a4ab62f1ab0da06f14bb69e382efecfb0deedc4c7f4b8cd"}, - {file = "playwright-1.47.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7fc820faf6885f69a52ba4ec94124e575d3c4a4003bf29200029b4a4f2b2d0ab"}, - {file = "playwright-1.47.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:8e212dc472ff19c7d46ed7e900191c7a786ce697556ac3f1615986ec3aa00341"}, - {file = "playwright-1.47.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:a1935672531963e4b2a321de5aa59b982fb92463ee6e1032dd7326378e462955"}, - {file = "playwright-1.47.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0a1b61473d6f7f39c5d77d4800b3cbefecb03344c90b98f3fbcae63294ad249"}, - {file = "playwright-1.47.0-py3-none-win32.whl", hash = "sha256:1b977ed81f6bba5582617684a21adab9bad5676d90a357ebf892db7bdf4a9974"}, - {file = "playwright-1.47.0-py3-none-win_amd64.whl", hash = "sha256:0ec1056042d2e86088795a503347407570bffa32cbe20748e5d4c93dba085280"}, + {file = "playwright-1.49.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:704532a2d8ba580ec9e1895bfeafddce2e3d52320d4eb8aa38e80376acc5cbb0"}, + {file = "playwright-1.49.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e453f02c4e5cc2db7e9759c47e7425f32e50ac76c76b7eb17c69eed72f01c4d8"}, + {file = "playwright-1.49.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:37ae985309184472946a6eb1a237e5d93c9e58a781fa73b75c8751325002a5d4"}, + {file = "playwright-1.49.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:68d94beffb3c9213e3ceaafa66171affd9a5d9162e0c8a3eed1b1132c2e57598"}, + {file = "playwright-1.49.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f12d2aecdb41fc25a624cb15f3e8391c252ebd81985e3d5c1c261fe93779345"}, + {file = "playwright-1.49.0-py3-none-win32.whl", hash = "sha256:91103de52d470594ad375b512d7143fa95d6039111ae11a93eb4fe2f2b4a4858"}, + {file = "playwright-1.49.0-py3-none-win_amd64.whl", hash = "sha256:34d28a2c2d46403368610be4339898dc9c34eb9f7c578207b4715c49743a072a"}, ] [package.dependencies] -greenlet = "3.0.3" +greenlet = "3.1.1" pyee = "12.0.0" [[package]] @@ -787,19 +792,19 @@ files = [ [[package]] name = "pydantic" -version = "2.9.2" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, - {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.23.4" -typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""} +pydantic-core = "2.27.1" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -807,100 +812,111 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.4" +version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, - {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, - {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, - {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, - {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, - {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, - {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, - {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, - {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, - {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, - {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, - {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, - {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, - {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, + {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, + {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, + {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, + {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, + {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, + {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, + {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, + {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, + {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, + {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, + {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, + {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, + {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, + {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, + {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, + {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, ] [package.dependencies] @@ -949,26 +965,24 @@ files = [ ] [package.dependencies] -Pillow = {version = ">=9.2.0", markers = "python_version == \"3.10\""} +Pillow = {version = ">=9.3.0", markers = "python_version == \"3.11\""} [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -1177,7 +1191,6 @@ files = [ [package.dependencies] psutil = ">=5.9,<6.0" -tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} [[package]] name = "robocorp-log-pytest" @@ -1242,88 +1255,79 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] [[package]] name = "ruamel-yaml-clib" -version = "0.2.8" +version = "0.2.12" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, - {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, - {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, + {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, ] [[package]] name = "ruff" -version = "0.6.8" +version = "0.6.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.8-py3-none-linux_armv6l.whl", hash = "sha256:77944bca110ff0a43b768f05a529fecd0706aac7bcce36d7f1eeb4cbfca5f0f2"}, - {file = "ruff-0.6.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27b87e1801e786cd6ede4ada3faa5e254ce774de835e6723fd94551464c56b8c"}, - {file = "ruff-0.6.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd48f945da2a6334f1793d7f701725a76ba93bf3d73c36f6b21fb04d5338dcf5"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:677e03c00f37c66cea033274295a983c7c546edea5043d0c798833adf4cf4c6f"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f1476236b3eacfacfc0f66aa9e6cd39f2a624cb73ea99189556015f27c0bdeb"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f5a2f17c7d32991169195d52a04c95b256378bbf0de8cb98478351eb70d526f"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5fd0d4b7b1457c49e435ee1e437900ced9b35cb8dc5178921dfb7d98d65a08d0"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8034b19b993e9601f2ddf2c517451e17a6ab5cdb1c13fdff50c1442a7171d87"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cfb227b932ba8ef6e56c9f875d987973cd5e35bc5d05f5abf045af78ad8e098"}, - {file = "ruff-0.6.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef0411eccfc3909269fed47c61ffebdcb84a04504bafa6b6df9b85c27e813b0"}, - {file = "ruff-0.6.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:007dee844738c3d2e6c24ab5bc7d43c99ba3e1943bd2d95d598582e9c1b27750"}, - {file = "ruff-0.6.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ce60058d3cdd8490e5e5471ef086b3f1e90ab872b548814e35930e21d848c9ce"}, - {file = "ruff-0.6.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1085c455d1b3fdb8021ad534379c60353b81ba079712bce7a900e834859182fa"}, - {file = "ruff-0.6.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:70edf6a93b19481affd287d696d9e311388d808671bc209fb8907b46a8c3af44"}, - {file = "ruff-0.6.8-py3-none-win32.whl", hash = "sha256:792213f7be25316f9b46b854df80a77e0da87ec66691e8f012f887b4a671ab5a"}, - {file = "ruff-0.6.8-py3-none-win_amd64.whl", hash = "sha256:ec0517dc0f37cad14a5319ba7bba6e7e339d03fbf967a6d69b0907d61be7a263"}, - {file = "ruff-0.6.8-py3-none-win_arm64.whl", hash = "sha256:8d3bb2e3fbb9875172119021a13eed38849e762499e3cfde9588e4b4d70968dc"}, - {file = "ruff-0.6.8.tar.gz", hash = "sha256:a5bf44b1aa0adaf6d9d20f86162b34f7c593bfedabc51239953e446aefc8ce18"}, + {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, + {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, + {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, + {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, + {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, + {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, + {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, ] [[package]] @@ -1383,13 +1387,10 @@ name = "sema4ai-python-ls-core" version = "0.0.1" description = "Robocorp python language server core components" optional = false -python-versions = ">=3.10,<3.11" +python-versions = ">=3.11,<3.12" files = [] develop = true -[package.dependencies] -tomli = {version = "^2.0.1", markers = "python_version < \"3.11\""} - [package.source] type = "directory" url = "../sema4ai-python-ls-core" @@ -1432,29 +1433,18 @@ widechars = ["wcwidth"] [[package]] name = "termcolor" -version = "2.4.0" +version = "2.5.0" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, + {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, + {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, ] [package.extras] tests = ["pytest", "pytest-cov"] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "tomlkit" version = "0.11.8" @@ -1540,13 +1530,13 @@ files = [ [[package]] name = "types-docutils" -version = "0.21.0.20240907" +version = "0.21.0.20241128" description = "Typing stubs for docutils" optional = false python-versions = ">=3.8" files = [ - {file = "types-docutils-0.21.0.20240907.tar.gz", hash = "sha256:5dd2aa5e2e06fcfa090020bc4115479b4dd28da3329ab708563ee29894bd3c0d"}, - {file = "types_docutils-0.21.0.20240907-py3-none-any.whl", hash = "sha256:9c8ed6d90583944af00f6b5fa3aecc2101e20672f6b1a4a299c6bf7d1e47084d"}, + {file = "types_docutils-0.21.0.20241128-py3-none-any.whl", hash = "sha256:e0409204009639e9b0bf4521eeabe58b5e574ce9c0db08421c2ac26c32be0039"}, + {file = "types_docutils-0.21.0.20241128.tar.gz", hash = "sha256:4dd059805b83ac6ec5a223699195c4e9eeb0446a4f7f2aeff1759a4a7cc17473"}, ] [[package]] @@ -1656,5 +1646,5 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" -python-versions = ">=3.10,<3.11" -content-hash = "197e7976fd2380d4c9e1f3041d85ef7af1444638584a94a1c125c5aab32b2870" +python-versions = ">=3.11,<3.12" +content-hash = "0dc5a2e5b00c75856a9b40ac00db70762a51219c564139c94b84c9637684653d" diff --git a/sema4ai/pyproject.toml b/sema4ai/pyproject.toml index 3bca632aa..a05de3a21 100644 --- a/sema4ai/pyproject.toml +++ b/sema4ai/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ ] [tool.poetry.dependencies] -python = ">=3.10,<3.11" +python = ">=3.11,<3.12" tomli = { version = "^2.0.1", python = "<3.11" } msgspec = "^0.18" pyyaml = "^6" @@ -44,6 +44,7 @@ ruff = "^0.6.5" tree-sitter = "^0.22.3" tree-sitter-yaml = "^0.6.0" ruamel-yaml = "^0.18.6" +sema4ai-http-helper = "^1.0.2" [tool.poetry.group.dev.dependencies] sema4ai-python-ls-core = { path = "../sema4ai-python-ls-core/", develop = true } @@ -61,7 +62,6 @@ isort = { version = "^5.12.0", python = "^3.8" } invoke = "^2.0" tomlkit = "^0.11.8" semver = "^3.0.0" -robocorp-truststore = "0.9.1" mock = "*" pytest = "*" diff --git a/sema4ai/src/sema4ai_code/action_server.py b/sema4ai/src/sema4ai_code/action_server.py index c6dcab83c..541606a0f 100644 --- a/sema4ai/src/sema4ai_code/action_server.py +++ b/sema4ai/src/sema4ai_code/action_server.py @@ -18,10 +18,9 @@ ) from sema4ai_code.protocols import ( - ActionServerListOrgsResultDict, - ActionServerPackageBuildResultDict, - ActionServerPackageUploadStatusDict, - ActionServerVerifyLoginResultDict, + ActionServerPackageBuildInfo, + ActionServerPackageUploadStatus, + ActionServerVerifyLoginInfoDict, ActionTemplate, ) @@ -228,26 +227,12 @@ def _urlopen_kwargs(self, **kwargs) -> dict: f"Expected: {cert_file_path} to exist (it should've been created " "when the action server is started with the option to use a self-signed certificate)." ) - # Create a context with certificate verification - try: - import truststore - - truststore.extract_from_ssl() - except Exception: - pass - from ssl import Purpose ctx = ssl.create_default_context(Purpose.SERVER_AUTH) ctx.load_verify_locations(cert_file_path) kwargs["context"] = ctx - try: - import truststore - - truststore.inject_into_ssl() - except Exception: - pass return kwargs def build_full_url(self, url: str) -> str: @@ -719,7 +704,7 @@ def cloud_login(self, access_credentials: str, hostname: str) -> ActionResult: message=f"Error login to Control Room.\n{command_result.message or ''}", ) - def verify_login(self) -> ActionResult[ActionServerVerifyLoginResultDict]: + def verify_login(self) -> ActionResult[ActionServerVerifyLoginInfoDict]: """ Verify authentication information from the Control Room for action server. """ @@ -751,7 +736,7 @@ def verify_login(self) -> ActionResult[ActionServerVerifyLoginResultDict]: def list_organizations( self, access_credentials: str | None, hostname: str | None - ) -> ActionResult[ActionServerListOrgsResultDict]: + ) -> ActionResult[list[str]]: """ List available organizations with access credentials used at login. """ @@ -783,7 +768,7 @@ def list_organizations( def package_build( self, workspace_dir: str, output_dir: str - ) -> ActionResult[ActionServerPackageBuildResultDict]: + ) -> ActionResult[ActionServerPackageBuildInfo]: """ Build action package. @@ -833,7 +818,7 @@ def package_upload( organization_id: str, access_credentials: str | None, hostname: str | None, - ) -> ActionResult[ActionServerPackageUploadStatusDict]: + ) -> ActionResult[ActionServerPackageUploadStatus]: """ Upload action package to Control Room. @@ -887,7 +872,7 @@ def package_status( organization_id: str, access_credentials: str | None, hostname: str | None, - ) -> ActionResult[ActionServerPackageUploadStatusDict]: + ) -> ActionResult[ActionServerPackageUploadStatus]: """ Get uploaded action package status from Control Room. @@ -1010,23 +995,3 @@ def package_metadata( success=False, message=f"Error creating the metadata file.\n{command_result.message or ''}", ) - - -if __name__ == "__main__": - import truststore - - # It seems that if trustore is installed we can't use a self-signed - # certificate to access the action server unless it's actually installed - # in the computer. - truststore.extract_from_ssl() - - s = ActionServerAsService( - "", cwd=".", port=4567, use_https=True, ssl_self_signed=True - ) - print(s.get_config(timeout=10)) - - truststore.inject_into_ssl() - s = ActionServerAsService( - "", cwd=".", port=4567, use_https=True, ssl_self_signed=True - ) - print(s.get_config(timeout=10)) diff --git a/sema4ai/src/sema4ai_code/commands.py b/sema4ai/src/sema4ai_code/commands.py index 5ebce0025..dd1c59c99 100644 --- a/sema4ai/src/sema4ai_code/commands.py +++ b/sema4ai/src/sema4ai_code/commands.py @@ -147,8 +147,6 @@ SEMA4AI_IMPORT_ACTION_PACKAGE = "sema4ai.importActionPackage" # Import Action Package SEMA4AI_RUN_ACTION_PACKAGE_DEV_TASK = "sema4ai.runActionPackageDevTask" # Run dev-task (from Action Package) SEMA4AI_GET_ACTIONS_METADATA = "sema4ai.getActionsMetadata" # Get Actions Metadata -SEMA4AI_START_DATA_SERVER = "sema4ai.startDataServer" # Start Data Server -SEMA4AI_STOP_DATA_SERVER = "sema4ai.stopDataServer" # Stop Data Server ALL_SERVER_COMMANDS = [ SEMA4AI_GET_PLUGINS_DIR, diff --git a/sema4ai/src/sema4ai_code/data/data_server_connection.py b/sema4ai/src/sema4ai_code/data/data_server_connection.py new file mode 100644 index 000000000..d432b63fd --- /dev/null +++ b/sema4ai/src/sema4ai_code/data/data_server_connection.py @@ -0,0 +1,212 @@ +import logging +import typing +from pathlib import Path +from typing import Any, Optional + +if typing.TYPE_CHECKING: + from .result_set import ResultSet + +log = logging.getLogger(__name__) + + +class _HttpConnectionHelper: + """ + Helper class to manage connections to the http server. + """ + + def __init__(self, http_url: str, http_user: str, http_password: str) -> None: + self._http_url = http_url + self._http_user = http_user + self._http_password = http_password + self._session_headers: dict[str, str] = {} + + def login(self) -> None: + from http.cookies import SimpleCookie + + import sema4ai_http + + login_url = f"{self._http_url}/api/login" + + login_response = sema4ai_http.post( + login_url, + json={"password": self._http_password, "username": self._http_user}, + ) + + if login_response.status != 200: + raise Exception( + f"Failed to login. Status: {login_response.status}. Data: {login_response.data.decode('utf-8', errors='backslashreplace')}" + ) + + cookies = SimpleCookie() + session_cookies = {} + if "set-cookie" in login_response.headers: + cookies.load(login_response.headers["set-cookie"]) + session_cookies = {key: morsel.value for key, morsel in cookies.items()} + cookie_header = "; ".join([f"{k}={v}" for k, v in session_cookies.items()]) + self._session_headers = {"Cookie": cookie_header} + + def _is_login_info_available(self) -> bool: + return bool(self._http_user and self._http_password) + + def _login_if_needed(self) -> None: + if not self._session_headers and self._is_login_info_available(): + self.login() + + def upload_file(self, file_path: Path, table_name: str) -> None: + self._login_if_needed() + try: + self._upload_file(file_path, table_name) + except Exception: + if not self._is_login_info_available(): + raise + + # Retry once with a new session + self._session_headers = {} + self._login_if_needed() + self._upload_file(file_path, table_name) + + def run_sql( + self, sql: str, database: str | None = None + ) -> tuple[list[str], list[list[Any]]] | None: + """ + Args: + sql: + database: + + Returns: + A tuple of columns and rows. + """ + import sema4ai_http + + log.info(f"Running sql:\n{sql}") + self._login_if_needed() + + url = self._http_url + "/api/sql/query" + + result = sema4ai_http.post( + url, + json={"query": sql, "context": {"db": database or ""}}, + headers=self._session_headers, + ) + if result.status != 200: + raise Exception( + f"Failed to run sql. Status: {result.status}. Data: {result.data.decode('utf-8', errors='backslashreplace')}" + ) + + data = result.json() + data_type = data["type"] + if data_type == "table": + columns: list[str] = [x for x in data["column_names"]] + rows: list[list[Any]] = data["data"] + return columns, rows + if data_type == "ok": + return None + if data_type == "error": + raise RuntimeError(data["error_message"]) + log.debug(f"Unexpected sql result type: {data_type}") + return None + + def _upload_file(self, file_path: Path, table_name: str) -> None: + import json + + import sema4ai_http + + file_name = file_path.name + data = file_path.read_bytes() + result = sema4ai_http.put( + f"{self._http_url}/api/files/{table_name}", + fields={ + "file": (file_name, data), + "data": json.dumps( + { + "original_file_name": file_name, + "name": table_name, + "source_type": "file", + } + ).encode("utf-8"), + }, + headers=self._session_headers, + ) + if result.status != 200: + raise Exception( + f"Failed to upload file. Status: {result.status}. Data: {result.data.decode('utf-8', errors='backslashreplace')}" + ) + + +class DataServerConnection: + def __init__( + self, http_url: str, http_user: Optional[str], http_password: Optional[str] + ): + """ + Creates a connection to the data server. + """ + # Not using mysql connection for now (had issues with pymysql not giving + # errors when the connection was closed by the server). + self._http_connection = _HttpConnectionHelper( + http_url, http_user or "", http_password or "" + ) + + def login(self) -> None: + self._http_connection.login() + + def query( + self, + database_name: str, + query: str, + params: Optional[dict[str, str | int | float] | list[str | int | float]] = None, + ) -> "ResultSet": + """ + Simple API to query a database in MindsDB with parameters. Always loads + all the results into memory. + + Args: + database_name: The name of the database to query. + query: The SQL query to execute. + params: A list of parameters to inject into the query. + + Returns: + ResultSet: The query result as a ResultSet. + """ + from .result_set import ResultSet + from .sql_handling import ( + build_query_from_dict_params, + build_query_from_list_params, + ) + + if isinstance(params, list): + query = build_query_from_list_params(query, params) + else: + query = build_query_from_dict_params(query, params) + + result = self._http_connection.run_sql(query, database_name) + if result is None: + raise RuntimeError( + "Unexpected result from the data server (expected table but received just 'ok')" + ) + + columns, rows = result + return ResultSet([x.lower() for x in columns], [tuple(row) for row in rows]) + + # It's actually the same thing internally, so we can just alias it. + predict = query + + def run_sql( + self, + sql: str, + params: Optional[dict[str, str | int | float] | list[str | int | float]] = None, + ) -> None: + database_name = "" + from .sql_handling import ( + build_query_from_dict_params, + build_query_from_list_params, + ) + + if isinstance(params, list): + sql = build_query_from_list_params(sql, params) + else: + sql = build_query_from_dict_params(sql, params) + + self._http_connection.run_sql(sql, database_name) + + def upload_file(self, file_path: Path, table_name: str) -> None: + self._http_connection.upload_file(file_path, table_name) diff --git a/sema4ai/src/sema4ai_code/data/result_set.py b/sema4ai/src/sema4ai_code/data/result_set.py new file mode 100644 index 000000000..dc8663a29 --- /dev/null +++ b/sema4ai/src/sema4ai_code/data/result_set.py @@ -0,0 +1,42 @@ +import typing +from typing import Any, Iterator + +T = typing.TypeVar("T") + + +class ResultSet: + def __init__(self, columns: list[str], rows: list[tuple[Any, ...]]): + self._columns = tuple(columns) + self._data = rows + + def iter_as_dicts(self) -> Iterator[dict[str, Any]]: + """ + Iterates over the result set as a list of dictionaries. + """ + for row in self._data: + yield dict(zip(self._columns, row)) + + def iter_as_tuples(self) -> Iterator[tuple[Any, ...]]: + """ + Iterates over the result set values as a list of tuples. + """ + yield from self._data + + def build_list(self, item_class: type[T]) -> list[T]: + """ + Builds a list of objects of the given class from the result set. + + Args: + item_class: The class to build the list of. + + Returns: + A list of objects of the given class. + + Note: The class must have a constructor that accepts each item in the + result set as keyword arguments. + """ + return [item_class(**row) for row in self.iter_as_dicts()] + + @property + def columns(self) -> tuple[str, ...]: + return self._columns diff --git a/sema4ai/src/sema4ai_code/data/sql_handling.py b/sema4ai/src/sema4ai_code/data/sql_handling.py new file mode 100644 index 000000000..a8dd16d51 --- /dev/null +++ b/sema4ai/src/sema4ai_code/data/sql_handling.py @@ -0,0 +1,109 @@ +from typing import Optional + + +def build_query_from_dict_params( + query: str, params: Optional[dict[str, str | int | float]] +) -> str: + """ + Replace all the $name in the query with the actual values from params. + + Args: + query: The SQL query with placeholders. + params: A dictionary of parameters to inject into the query. + + Returns: + str: The query with parameters injected. + """ + import math + import re + + if not params and "$" not in query: + return query + + new_params: dict[str, str] = {} + if params: + # Escape single quotes in parameters to prevent SQL injection + C1 = "'" + C2 = "''" + for key, value in params.items(): + if isinstance(value, str): + value = value.replace(C1, C2) + new_params[key] = f"'{value}'" + elif isinstance(value, (int, float)): + if not math.isfinite(value): + raise ValueError( + f"Infinity or NaN is not supported as a query parameter. Parameters: {params}" + ) + new_params[key] = str(value) + else: + raise ValueError(f"Unsupported parameter: {value} type: {type(value)}") + + # Replace placeholders with actual values + def replace_placeholder(match): + key = match.group(1) + if key in new_params: + return new_params[key] + raise ValueError(f"Missing parameter for placeholder: {key}") + + # Use regex to find all placeholders and replace them + query = re.sub(r"\$(\w+)", replace_placeholder, query) + + return query + + +def build_query_from_list_params( + query: str, params: Optional[list[str | int | float]] +) -> str: + """ + Replace all the ? in the query with the actual values from params. + + Args: + query: The SQL query with placeholders. + params: A list of parameters to inject into the query. + + Returns: + str: The query with parameters injected. + """ + import math + + placeholder_count = query.count("?") + params_len = len(params) if params else 0 + + # Check if the number of placeholders matches the number of parameters + if placeholder_count != params_len: + raise ValueError( + f"The number of placeholders ({placeholder_count}) does not match the number of parameters ({params_len})." + ) + + if not params: + return query + + # Escape single quotes in parameters to prevent SQL injection + C1 = "'" + C2 = "''" + escaped_params = [] + for param in params: + if isinstance(param, str): + new_param = param.replace(C1, C2) + escaped_params.append(f"'{new_param}'") + elif isinstance(param, (int, float)): + # Assert that it's not infinity or NaN + if not math.isfinite(param): + raise ValueError( + f"Infinity or NaN is not supported as a query parameter. Parameters: {params}" + ) + v = str(param) + escaped_params.append(v) + else: + raise ValueError(f"Unsupported parameter: {param} type: {type(param)}") + + # Split the query by placeholders and interleave with parameters + parts = query.split("?") + query_with_params = "".join( + part + param for part, param in zip(parts, escaped_params) + ) + + if parts[-1] != "": # If the last part is not empty, add it too + query_with_params += parts[-1] + + return query_with_params diff --git a/sema4ai/src/sema4ai_code/inspector/inspector_language_server.py b/sema4ai/src/sema4ai_code/inspector/inspector_language_server.py index ac83938a4..accba0bbc 100644 --- a/sema4ai/src/sema4ai_code/inspector/inspector_language_server.py +++ b/sema4ai/src/sema4ai_code/inspector/inspector_language_server.py @@ -1,11 +1,10 @@ import weakref from functools import partial from pathlib import Path -from typing import Literal, Optional +from typing import Literal -from sema4ai_ls_core.protocols import ActionResultDict from sema4ai_ls_core.core_log import get_logger - +from sema4ai_ls_core.protocols import ActionResultDict log = get_logger(__name__) @@ -69,6 +68,7 @@ def m_manager_save_locator( } return ret locators = loaded_locators_action_result["result"] + assert locators is not None, "Locators should not be None" locators[name] = locator @@ -120,6 +120,13 @@ def m_manager_delete_locators( return ret locators = loaded_locators_action_result["result"] + if locators is None: + ret = { + "success": False, + "message": "Locators not properly loaded (status was success but result was None).", + "result": None, + } + return ret for locator_id in ids: locators.pop(locator_id, None) diff --git a/sema4ai/src/sema4ai_code/protocols.py b/sema4ai/src/sema4ai_code/protocols.py index c18376c75..2d407f26c 100644 --- a/sema4ai/src/sema4ai_code/protocols.py +++ b/sema4ai/src/sema4ai_code/protocols.py @@ -79,64 +79,27 @@ class ActionServerVerifyLoginInfoDict(TypedDict): T = TypeVar("T") -class ActionResultDictRobotLaunch(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: dict[str, Any] | None +ActionResultDictRobotLaunch = ActionResultDict[dict[str, Any]] +ActionResultDictLocatorsJson = ActionResultDict[tuple[Any, Path]] -class ActionResultDictLocatorsJson(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: tuple[Any, Path] | None +ActionResultDictLocatorsJsonInfo = ActionResultDict[list[LocatorEntryInfoDict]] +ActionResultDictLocalRobotMetadata = ActionResultDict[ + list[LocalPackageMetadataInfoDict] +] -class ActionResultDictLocatorsJsonInfo(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: list[LocatorEntryInfoDict] | None +ActionServerVerifyLoginResultDict = ActionResultDict[ActionServerVerifyLoginInfoDict] -class ActionResultDictLocalRobotMetadata(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: list[LocalPackageMetadataInfoDict] | None - - -class ActionServerVerifyLoginResultDict(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: ActionServerVerifyLoginInfoDict | None - - -class ActionServerListOrgsResultDict(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: list[str] | None +ActionServerListOrgsResultDict = ActionResultDict[list[str]] class ActionServerPackageBuildInfo(TypedDict): package_path: str -class ActionServerPackageBuildResultDict(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: ActionServerPackageBuildInfo +ActionServerPackageBuildResultDict = ActionResultDict[ActionServerPackageBuildInfo] class ActionPackageUploadStatusError(TypedDict): @@ -161,12 +124,7 @@ class ActionServerPackageUploadStatus(TypedDict): error: ActionPackageUploadStatusError | None -class ActionServerPackageUploadStatusDict(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: ActionServerPackageUploadStatus +ActionServerPackageUploadStatusDict = ActionResultDict[ActionServerPackageUploadStatus] class WorkItem(TypedDict): @@ -189,12 +147,7 @@ class WorkItemsInfo(TypedDict): new_output_workitem_path: str -class ActionResultDictWorkItems(TypedDict): - success: bool - message: None | ( - str - ) # if success == False, this can be some message to show to the user - result: WorkItemsInfo | None +ActionResultDictWorkItems = ActionResultDict[WorkItemsInfo] class ListWorkItemsParams(TypedDict): @@ -555,3 +508,33 @@ def holotree_hash( file_path: str, ) -> ActionResult[str]: pass + + +class HttpConfigTypedDict(TypedDict): + host: str + port: str + + +class MysqlConfigTypedDict(TypedDict): + host: str + port: str + ssl: bool + + +class ApiConfigTypedDict(TypedDict): + http: HttpConfigTypedDict + mysql: MysqlConfigTypedDict + + +class AuthConfigTypedDict(TypedDict): + http_auth_enabled: bool + password: str + username: str + + +class DataServerConfigTypedDict(TypedDict): + api: ApiConfigTypedDict + auth: AuthConfigTypedDict + isRunning: bool + pid: int + pidFilePath: str diff --git a/sema4ai/src/sema4ai_code/robo/collect_actions_ast.py b/sema4ai/src/sema4ai_code/robo/collect_actions_ast.py index dc458a2ca..f611403e3 100644 --- a/sema4ai/src/sema4ai_code/robo/collect_actions_ast.py +++ b/sema4ai/src/sema4ai_code/robo/collect_actions_ast.py @@ -1,10 +1,12 @@ import ast as ast_module from collections.abc import Iterator from pathlib import Path -from typing import Any, TypedDict +from typing import Any, Literal, TypedDict from sema4ai_ls_core import uris from sema4ai_ls_core.core_log import get_logger +from sema4ai_ls_core.lsp import RangeTypedDict +from sema4ai_ls_core.protocols import ActionInfoTypedDict, DatasourceInfoTypedDict log = get_logger(__name__) @@ -89,10 +91,22 @@ def _resolve_value(node: ast_module.AST, variable_values: dict[str, str]) -> str return None -DATASOURCE_KIND = "datasource" +class _DatasourceInfo(TypedDict, total=False): + kind: Literal["datasource"] + node: ast_module.AST + name: str | None + engine: str | None + model_name: str | None + created_table: str | None + python_variable_name: str -def _extract_datasource_info(call_node: ast_module.Call, variable_values: dict) -> dict: +def _extract_datasource_info( + call_node: ast_module.Call, + variable_values: dict, + python_variable_name: str, + target_node: ast_module.AST, +) -> _DatasourceInfo: """ Extract datasource information from a DataSourceSpec(...) call node. @@ -100,31 +114,80 @@ def _extract_datasource_info(call_node: ast_module.Call, variable_values: dict) call_node: AST node representing the call. variable_values: Dictionary of known variable values. """ + import typing + + collect_info = ("name", "model_name", "engine", "created_table") - interested_info = ["name", "model_name", "engine", "created_table"] - info = {"kind": DATASOURCE_KIND, "node": call_node} + info: _DatasourceInfo = {"kind": "datasource", "node": target_node} for keyword in call_node.keywords: - if keyword.arg in interested_info: + if keyword.arg in collect_info: + key = typing.cast( + Literal["name", "model_name", "engine", "created_table"], keyword.arg + ) name = _resolve_value(keyword.value, variable_values) - info[keyword.arg] = name + info[key] = name if info.get("engine") == "files": info["name"] = "files" elif info.get("model_name"): info["name"] = "models" + info["python_variable_name"] = python_variable_name + return info -def _collect_actions_from_ast( - p: Path, collect_datasources: bool = False -) -> Iterator[dict]: - action_contents_file = p.read_bytes() - ast = ast_module.parse(action_contents_file, "") - variables = _collect_variables(ast) +def is_annotated_type(node: ast_module.AST) -> bool: + if isinstance(node, ast_module.Name): + return node.id == "Annotated" + + if isinstance(node, ast_module.Attribute): + return node.attr == "Annotated" - for _stack, node in _iter_nodes(ast, recursive=True): + return False + + +def _collect_datasources( + ast: ast_module.AST, variables: dict[str, Any] +) -> Iterator[_DatasourceInfo]: + """ + Collect datasource information by identifying specific structures in the AST. + + Args: + ast: The root AST node. + variables: Dictionary of known variable values. + """ + for _stack, node in _iter_nodes(ast, recursive=False): + if isinstance(node, ast_module.Assign) and len(node.targets) == 1: + # Get the name of the variable being assigned + target = node.targets[0] + if isinstance(target, ast_module.Name) and isinstance( + node.value, ast_module.Subscript + ): + python_variable_name = target.id + subscript = node.value + # Check if the value is an Annotated[...] or typing.Annotated[...] + if is_annotated_type(subscript.value): + # Check if the slice is a Call node with DataSourceSpec + if isinstance(subscript.slice, ast_module.Tuple): + elts = subscript.slice.elts + if len(elts) == 2: + if isinstance(elts[1], ast_module.Call): + if ( + isinstance(elts[1].func, ast_module.Name) + and elts[1].func.id == "DataSourceSpec" + ): + yield _extract_datasource_info( + elts[1], + variables, + python_variable_name, + target_node=target, + ) + + +def _collect_actions_from_ast(ast: ast_module.AST) -> Iterator[dict]: + for _stack, node in _iter_nodes(ast, recursive=False): if isinstance(node, ast_module.FunctionDef): for decorator in node.decorator_list: if isinstance(decorator, ast_module.Call): @@ -138,100 +201,43 @@ def _collect_actions_from_ast( "predict", ]: yield {"node": node, "kind": decorator.id} - if ( - collect_datasources - and isinstance(node, ast_module.Call) - and isinstance(node.func, ast_module.Name) - and node.func.id == "DataSourceSpec" - ): - result = _extract_datasource_info(node, variables) - if result: - yield result - - -class PositionTypedDict(TypedDict): - # Line position in a document (zero-based). - line: int - - # Character offset on a line in a document (zero-based). Assuming that - # the line is represented as a string, the `character` value represents - # the gap between the `character` and `character + 1`. - # - # If the character value is greater than the line length it defaults back - # to the line length. - character: int - - -class RangeTypedDict(TypedDict): - start: PositionTypedDict - end: PositionTypedDict - - -class ActionInfoTypedDict(TypedDict): - range: RangeTypedDict - name: str - uri: str - kind: str - - -class DatasourceInfoTypedDict(ActionInfoTypedDict): - engine: str - model_name: str | None - created_table: str | None def _get_ast_node_range( - node: ast_module.FunctionDef | ast_module.Call, + node: ast_module.FunctionDef | ast_module.Call | ast_module.AST, ) -> RangeTypedDict: - coldelta = 4 - - if isinstance(node, ast_module.Call): - func_node = node.func + if isinstance(node, ast_module.FunctionDef): + coldelta = 4 return { "start": { - "line": func_node.lineno, - "character": func_node.col_offset, + "line": node.lineno, + "character": node.col_offset + coldelta, }, "end": { - "line": node.end_lineno or func_node.lineno, - "character": node.end_col_offset or node.col_offset, + "line": node.lineno, + "character": node.col_offset + coldelta + len(node.name), }, } + if isinstance(node, ast_module.Call): + node_expr = node.func + elif isinstance(node, ast_module.expr): + node_expr = node + else: + raise ValueError(f"Unexpected node type to get node range: {type(node)}") + return { "start": { - "line": node.lineno, - "character": node.col_offset + coldelta, + "line": node_expr.lineno, + "character": node_expr.col_offset, }, "end": { - "line": node.lineno, - "character": node.col_offset + coldelta + len(node.name), + "line": node_expr.end_lineno or node_expr.lineno, + "character": node_expr.end_col_offset or node_expr.col_offset, }, } -def _make_action_or_datasource_info( - uri: str, node_info: dict -) -> ActionInfoTypedDict | DatasourceInfoTypedDict: - ast_node = node_info["node"] - range = _get_ast_node_range(ast_node) - - if node_info["kind"] == DATASOURCE_KIND: - return DatasourceInfoTypedDict( - range=range, - uri=uri, - name=node_info["name"], - engine=node_info["engine"], - model_name=node_info.get("model_name"), - created_table=node_info.get("created_table"), - kind=node_info["kind"], - ) - else: - return ActionInfoTypedDict( - range=range, uri=uri, name=ast_node.name, kind=node_info["kind"] - ) - - DEFAULT_ACTION_SEARCH_GLOB = ( "*action*.py|*query*.py|*queries*.py|*predict*.py|*datasource*.py|*data_source*.py" ) @@ -255,10 +261,54 @@ def iter_actions_and_datasources( for glob in globs: if fnmatch.fnmatch(f.name, glob): try: - for node_info in _collect_actions_from_ast(f, collect_datasources): - yield _make_action_or_datasource_info( - uris.from_fs_path(str(f)), node_info + action_contents_file = f.read_bytes() + ast = ast_module.parse(action_contents_file, "") + uri = uris.from_fs_path(str(f)) + + for node_info_action in _collect_actions_from_ast(ast): + ast_node = node_info_action["node"] + node_range = _get_ast_node_range(ast_node) + yield ActionInfoTypedDict( + uri=uri, + range=node_range, + name=ast_node.name, + kind=node_info_action["kind"], ) + + if collect_datasources: + variables = _collect_variables(ast) + # Note: Instead of iterating over all nodes to collect datasources, we + # try to find the following structure: + # + # DataSourceVarName = Annotated[DataSource, DataSourceSpec(name="my_datasource")] + # + # Note that the DataSourceSpec(...) is a Call node inside the Annotated[...] + # which in turn must be inside an Assign node. + + if collect_datasources: + for node_info_datasource in _collect_datasources( + ast, variables + ): + ast_node = node_info_datasource["node"] + node_range = _get_ast_node_range(ast_node) + yield DatasourceInfoTypedDict( + range=node_range, + uri=uri, + name=node_info_datasource.get("name") + or "", + engine=node_info_datasource.get( + "engine", + ) + or "", + model_name=node_info_datasource.get("model_name"), + created_table=node_info_datasource.get( + "created_table" + ), + kind="datasource", + python_variable_name=node_info_datasource.get( + "python_variable_name" + ), + ) except Exception as e: log.error( f"Unable to collect @action/@query/@predict/datasources from {f}. Error: {e}" diff --git a/sema4ai/src/sema4ai_code/robocorp_language_server.py b/sema4ai/src/sema4ai_code/robocorp_language_server.py index c8b75f6d9..1fcb98d10 100644 --- a/sema4ai/src/sema4ai_code/robocorp_language_server.py +++ b/sema4ai/src/sema4ai_code/robocorp_language_server.py @@ -20,7 +20,12 @@ HoverTypedDict, TextDocumentCodeActionTypedDict, ) -from sema4ai_ls_core.protocols import IConfig, IMonitor, LibraryVersionInfoDict +from sema4ai_ls_core.protocols import ( + DataSourceStateDict, + IConfig, + IMonitor, + LibraryVersionInfoDict, +) from sema4ai_ls_core.python_ls import BaseLintManager, PythonLanguageServer from sema4ai_ls_core.watchdog_wrapper import IFSObserver @@ -53,6 +58,7 @@ CreateActionPackageParamsDict, CreateAgentPackageParamsDict, CreateRobotParamsDict, + DataServerConfigTypedDict, DownloadToolDict, IRccRobotMetadata, IRccWorkspace, @@ -79,6 +85,10 @@ if typing.TYPE_CHECKING: from sema4ai_code.agents.gallery_actions import GalleryActionPackages + from sema4ai_code.robo.collect_actions_ast import ( + ActionInfoTypedDict, + DatasourceInfoTypedDict, + ) log = get_logger(__name__) @@ -184,13 +194,6 @@ def __init__(self, read_stream, write_stream) -> None: f"Env vars info: {env_vars_info}\n" ) - try: - import truststore - - truststore.inject_into_ssl() - except Exception: - log.exception("There was an error injecting trustore into ssl.") - self._fs_observer: IFSObserver | None = None self._dir_cache = DirCache(cache_dir) @@ -664,7 +667,10 @@ def _cloud_list_workspaces( ret: list[WorkspaceInfoDict] = [] result = self._rcc.cloud_list_workspaces() if not result.success: - return result.as_dict() + # It's an error, so, the data should be None. + return typing.cast( + ActionResultDict[list[WorkspaceInfoDict]], result.as_dict() + ) workspaces = result.result for ws in workspaces or []: @@ -708,7 +714,10 @@ def _cloud_list_workspaces( ret.append(ws_dict) if not ret and last_error_result is not None: - return last_error_result.as_dict() + # It's an error, so, the data should be None. + return typing.cast( + ActionResultDict[list[WorkspaceInfoDict]], last_error_result.as_dict() + ) if ret: # Only store if we got something. store: ListWorkspaceCachedInfoDict = { @@ -810,40 +819,52 @@ def _list_actions_full_and_slow( @command_dispatcher(commands.SEMA4AI_LIST_ACTIONS_INTERNAL) def _local_list_actions_internal(self, params: ListActionsParams | None): # i.e.: should not block. - return partial(self._local_list_actions_internal_impl, params=params) + if not params: + msg = f"Unable to collect actions because no arguments were given." + return dict(success=False, message=msg, result=None) + + action_package_uri = params.get("action_package") + if not action_package_uri: + msg = f"Unable to collect actions because the target action_package was not given." + return dict(success=False, message=msg, result=None) + + collect_datasources = bool(params.get("collect_datasources", False)) + + return partial( + self._local_list_actions_internal_impl, + action_package_uri=action_package_uri, + collect_datasources=collect_datasources, + ) def _local_list_actions_internal_impl( - self, params: ListActionsParams | None - ) -> ActionResultDict: + self, action_package_uri: str, collect_datasources: bool + ) -> "ActionResultDict[list[ActionInfoTypedDict | DatasourceInfoTypedDict]]": from sema4ai_code.robo.collect_actions_ast import iter_actions_and_datasources # TODO: We should move this code somewhere else and have a cache of # things so that when the user changes anything the client is notified # about it. - if not params: - msg = f"Unable to collect actions because the target action package was not given." - return dict(success=False, message=msg, result=None) - - action_package_uri = params["action_package"] p = Path(uris.to_fs_path(action_package_uri)) if not p.exists(): - msg = f"Unable to collect actions from: {p} because it does not exist." - return dict(success=False, message=msg, result=None) + msg = f"Unable to collect actions/datasources from: {p} because it does not exist." + return ActionResult.make_failure(msg).as_dict() # type: ignore if not p.is_dir(): p = p.parent try: - actions = list( - iter_actions_and_datasources(p, bool(params["collect_datasources"])) + actions_and_datasources = list( + iter_actions_and_datasources(p, collect_datasources) ) except Exception as e: - log.exception("Error collecting actions.") + log.exception("Error collecting actions/datasources.") return dict( - success=False, message=f"Error collecting actions: {e}", result=None + success=False, + message=f"Error collecting actions/datasources: {e}", + result=None, ) - return dict(success=True, message=None, result=actions) + return dict(success=True, message=None, result=actions_and_datasources) @command_dispatcher(commands.SEMA4AI_LIST_WORK_ITEMS_INTERNAL) def _local_list_work_items_internal( @@ -1177,7 +1198,14 @@ def _compute_dev_task_spec_to_run_in_thread( return result try: - task_contents = result["result"][task_name] + dct = result["result"] + if dct is None: + return dict( + success=False, + message="Expected result to be a dict.", + result=None, + ) + task_contents = dct[task_name] except KeyError: return dict( success=False, @@ -2319,3 +2347,208 @@ def _import_zip_as_action_package( msg = f"Error importing action package: {str(e)}" log.exception(msg) return ActionResult.make_failure(msg).as_dict() + + def m_compute_data_source_state( + self, + action_package_yaml_directory_uri: str, + data_server_info: DataServerConfigTypedDict, + ): + return require_monitor( + partial( + self._compute_data_source_state_impl, + action_package_yaml_directory_uri, + data_server_info, + ) + ) + + def _compute_data_source_state_impl( + self, + action_package_yaml_directory_uri: str, + data_server_info: DataServerConfigTypedDict, + monitor: IMonitor, + ) -> ActionResultDict[DataSourceStateDict]: + try: + return self._impl_compute_data_source_state_impl( + action_package_yaml_directory_uri, data_server_info, monitor + ) + except Exception as e: + log.exception("Error computing data source state") + return ( + ActionResult[DataSourceStateDict] + .make_failure(f"Error computing data source state: {e}") + .as_dict() + ) + + def _impl_compute_data_source_state_impl( + self, + action_package_yaml_directory_uri: str, + data_server_info: DataServerConfigTypedDict, + monitor: IMonitor, + ) -> ActionResultDict[DataSourceStateDict]: + from sema4ai_ls_core.lsp import DiagnosticSeverity, DiagnosticsTypedDict + + from sema4ai_code.data.data_server_connection import DataServerConnection + + actions_and_datasources_result: ActionResultDict[ + "list[ActionInfoTypedDict | DatasourceInfoTypedDict]" + ] = self._local_list_actions_internal_impl( + action_package_uri=action_package_yaml_directory_uri, + collect_datasources=True, + ) + if not actions_and_datasources_result["success"]: + # Ok to cast as it's an error. + return typing.cast( + ActionResultDict[DataSourceStateDict], + actions_and_datasources_result, + ) + + http = data_server_info["api"]["http"] + auth = data_server_info["auth"] + user = auth["username"] + password = auth["password"] + + connection = DataServerConnection( + http_url=f"http://{http['host']}:{http['port']}", + http_user=user, + http_password=password, + ) + + result_set_projects = connection.query( + "", "SHOW DATABASES WHERE type = 'project'" + ) + result_set_not_projects = connection.query( + "", "SHOW DATABASES WHERE type != 'project'" + ) + projects_as_dicts = list(result_set_projects.iter_as_dicts()) + not_projects_as_dicts = list(result_set_not_projects.iter_as_dicts()) + + all_databases_as_dicts = projects_as_dicts + not_projects_as_dicts + + try: + data_source_names_in_data_server = set( + x["database"].lower() for x in all_databases_as_dicts + ) + except Exception: + log.exception( + "Error getting data source names in data server. Query result: %s", + all_databases_as_dicts, + ) + return ( + ActionResult[DataSourceStateDict] + .make_failure("Error getting data source names in data server") + .as_dict() + ) + + projects_data_source_names_in_data_server = set( + x["database"].lower() for x in projects_as_dicts + ) + + data_source_to_models = {} + for data_source in projects_data_source_names_in_data_server: + result_set_models = connection.query(data_source, "SELECT * FROM models") + if result_set_models: + data_source_to_models[data_source] = [ + x["name"] for x in result_set_models.iter_as_dicts() + ] + + files_table_names = set( + x["tables_in_files"] + for x in connection.query("files", "SHOW TABLES").iter_as_dicts() + ) + + assert actions_and_datasources_result["result"] is not None + actions_and_datasources: "list[ActionInfoTypedDict | DatasourceInfoTypedDict]" = actions_and_datasources_result[ + "result" + ] + required_data_sources: list["DatasourceInfoTypedDict"] = [ + typing.cast("DatasourceInfoTypedDict", d) + for d in actions_and_datasources + if d["kind"] == "datasource" + ] + + unconfigured_data_sources: list["DatasourceInfoTypedDict"] = [] + uri_to_error_messages: dict[str, list[DiagnosticsTypedDict]] = {} + ret: DataSourceStateDict = { + "unconfigured_data_sources": unconfigured_data_sources, + "uri_to_error_messages": uri_to_error_messages, + "required_data_sources": required_data_sources, + "data_sources_in_data_server": sorted(data_source_names_in_data_server), + } + + if required_data_sources: + datasource: "DatasourceInfoTypedDict" + for datasource in required_data_sources: + uri = datasource.get("uri", "") + datasource_name = datasource.get("name") + + if not datasource_name: + uri_to_error_messages.setdefault(uri, []).append( + { + "range": datasource["range"], + "severity": DiagnosticSeverity.Error, + "message": "It was not possible to statically discover the name of a datasource. Please specify the name of the datasource directly in the datasource definition.", + } + ) + continue + + datasource_engine = datasource.get("engine") + if not datasource_engine: + uri_to_error_messages.setdefault(uri, []).append( + { + "range": datasource["range"], + "severity": DiagnosticSeverity.Error, + "message": f"It was not possible to statically discover the engine of a datasource ({datasource_name}). Please specify the engine of the datasource directly in the datasource definition.", + } + ) + continue + + if datasource_engine == "files" or ( + datasource_name == "custom" and datasource.get("created_table") + ): + created_table = datasource.get("created_table") + if not created_table: + uri_to_error_messages.setdefault(uri, []).append( + { + "range": datasource["range"], + "severity": DiagnosticSeverity.Error, + "message": "The files engine requires the created_table field to be set.", + } + ) + continue + + if datasource_engine == "files": + if created_table not in files_table_names: + unconfigured_data_sources.append(datasource) + else: + # Custom datasource with created_table. + custom_table_names = set( + x["tables_in_files"] + for x in connection.query( + "files", "SHOW TABLES" + ).iter_as_dicts() + ) + if created_table not in custom_table_names: + unconfigured_data_sources.append(datasource) + continue + + if datasource_engine.startswith("prediction:") or ( + datasource_name == "custom" and datasource.get("model_name") + ): + model_name = datasource.get("model_name") + if not model_name: + uri_to_error_messages.setdefault(uri, []).append( + { + "range": datasource["range"], + "severity": DiagnosticSeverity.Error, + "message": "The prediction engine requires the model_name field to be set.", + } + ) + continue + if model_name not in data_source_to_models.get(datasource_name, []): + unconfigured_data_sources.append(datasource) + continue + + if datasource_name.lower() not in data_source_names_in_data_server: + unconfigured_data_sources.append(datasource) + + return ActionResult[DataSourceStateDict].make_success(ret).as_dict() diff --git a/sema4ai/tests/conftest.py b/sema4ai/tests/conftest.py index 9b59ac3af..88771e0b1 100644 --- a/sema4ai/tests/conftest.py +++ b/sema4ai/tests/conftest.py @@ -1,5 +1,6 @@ pytest_plugins = [ "sema4ai_code_tests.fixtures", + "sema4ai_code_tests.data_server_fixtures", "sema4ai_ls_core.unittest_tools.fixtures", "sema4ai_code_debug_adapter_tests.fixtures", ] diff --git a/sema4ai/tests/pytest.ini b/sema4ai/tests/pytest.ini index 2dbc90cc9..d2095193f 100644 --- a/sema4ai/tests/pytest.ini +++ b/sema4ai/tests/pytest.ini @@ -1,3 +1,7 @@ [pytest] -timeout=1200 +timeout=1800 ; addopts=-n 0 + +; https://docs.pytest.org/en/stable/how-to/mark.html +markers = + data_server: marks data server tests (deselect with '-m "not data_server"') diff --git a/sema4ai/tests/sema4ai_code_tests/data_server_cli_wrapper.py b/sema4ai/tests/sema4ai_code_tests/data_server_cli_wrapper.py new file mode 100644 index 000000000..9f52ea725 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/data_server_cli_wrapper.py @@ -0,0 +1,207 @@ +import logging +from pathlib import Path +from typing import TypedDict + +log = logging.getLogger(__name__) + + +def get_release_artifact_relative_path(sys_platform: str, executable_name: str) -> str: + """ + Helper function for getting the release artifact relative path as defined in S3 bucket. + + Args: + sys_platform: Platform for which the release artifact is being retrieved. + executable_name: Name of the executable we want to get the path for. + """ + import platform + + machine = platform.machine() + is_64 = not machine or "64" in machine + + if sys_platform == "win32": + if is_64: + return f"windows64/{executable_name}.exe" + else: + return f"windows32/{executable_name}.exe" + + elif sys_platform == "darwin": + return f"macos64/{executable_name}" + + else: + if is_64: + return f"linux64/{executable_name}" + else: + return f"linux32/{executable_name}" + + +class HttpNamedTypedDict(TypedDict): + host: str + port: str + + +class MysqlNamedTypedDict(TypedDict): + database: str + host: str + port: str + ssl: bool + + +class ApiNamedTypedDict(TypedDict): + http: HttpNamedTypedDict + mysql: MysqlNamedTypedDict + + +class AuthNamedTypedDict(TypedDict): + http_auth_enabled: bool + password: str + username: str + + +class LaunchJsonDataTypedDict(TypedDict): + api: ApiNamedTypedDict + auth: AuthNamedTypedDict + isRunning: bool + pid: int + pidFilePath: str + + +class LaunchJsonTypedDict(TypedDict): + success: bool + data: LaunchJsonDataTypedDict + + +# { +# "success": true, +# "data": { +# "api": { +# "http": { +# "host": "127.0.0.1", +# "port": "47334" +# }, +# "mysql": { +# "database": "mindsdb", +# "host": "127.0.0.1", +# "port": "47335", +# "ssl": false +# } +# }, +# "auth": { +# "http_auth_enabled": false, +# "password": "", +# "username": "mindsdb" +# }, +# "isRunning": true, +# "pid": 14848, +# "pidFilePath": "%localappdata%\\sema4ai\\data-server\\data_server.pid" +# } +# } + + +class DataServerCliWrapper: + VERSION = "1.0.2" + + def __init__(self, tmpdir: Path) -> None: + from typing import Optional + + self.target = self.get_default_target() + self._launch_json: Optional[LaunchJsonTypedDict] = None + self._tmpdir = tmpdir + from sema4ai_code.data.data_server_connection import DataServerConnection + + self.http_connection: Optional[DataServerConnection] = None + + @property + def launch_json(self) -> LaunchJsonTypedDict: + if self._launch_json is None: + raise RuntimeError("Data server cli not started") + return self._launch_json + + def get_default_target(self) -> Path: + import os + import sys + + if sys.platform == "win32": + localappdata = os.environ.get("LOCALAPPDATA") + if not localappdata: + raise RuntimeError("Error. LOCALAPPDATA not defined in environment!") + home = Path(localappdata) / "sema4ai" + else: + # Linux/Mac + home = Path("~/.sema4ai").expanduser() + + directory = home / "data-server-cli" / self.VERSION + directory.mkdir(parents=True, exist_ok=True) + executable_name = "data-server-cli" + if sys.platform == "win32": + executable_name += ".exe" + ret = directory / executable_name + return ret + + def download_data_server_cli(self): + if self.target.exists(): + return + + import sys + + relative_path = get_release_artifact_relative_path( + sys.platform, "data-server-cli" + ) + url = ( + f"https://cdn.sema4.ai/data-server-cli/beta/v{self.VERSION}/{relative_path}" + ) + import sema4ai_http + + result = sema4ai_http.download_with_resume( + url, self.target, make_executable=True + ) + assert result.status in ( + sema4ai_http.DownloadStatus.DONE, + sema4ai_http.DownloadStatus.ALREADY_EXISTS, + ) + + def start(self): + import json + import subprocess + import time + + log.info(f"Starting data server cli at {self.target}") + curtime = time.time() + output = subprocess.check_output( + [self.target, "launch", "-i", "-j", "--wait"], + cwd=self._tmpdir, + stderr=subprocess.PIPE, + ) + log.info(f"Time taken: {time.time() - curtime} seconds") + contents = output.decode("utf-8") + json_contents = json.loads(contents) + + if not json_contents.get("success"): + raise RuntimeError(f"Failed to launch data server cli: {contents}") + + self._launch_json = json_contents + + def print_log(self): + import subprocess + + process = subprocess.Popen( + [self.target, "log"], + cwd=self._tmpdir, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + stdout, _ = process.communicate() + # Print the last 100 lines + log_contents = "\n".join(stdout.decode("utf-8").splitlines()[-100:]) + print(log_contents) + + def get_username(self) -> str: + return self.launch_json["data"]["auth"]["username"] + + def get_password(self) -> str: + return self.launch_json["data"]["auth"]["password"] + + def get_http_and_mysql_ports(self) -> tuple[int, int]: + return ( + int(self.launch_json["data"]["api"]["http"]["port"]), + int(self.launch_json["data"]["api"]["mysql"]["port"]), + ) diff --git a/sema4ai/tests/sema4ai_code_tests/data_server_fixtures.py b/sema4ai/tests/sema4ai_code_tests/data_server_fixtures.py new file mode 100644 index 000000000..95f92a715 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/data_server_fixtures.py @@ -0,0 +1,273 @@ +from contextlib import contextmanager +from pathlib import Path +from typing import TYPE_CHECKING, Callable, Iterator + +import pytest + +if TYPE_CHECKING: + from sema4ai_code_tests.data_server_cli_wrapper import DataServerCliWrapper + + from sema4ai_code.data.data_server_connection import DataServerConnection + +INSERT_SQL_DATA = [ + ("Alice", 30), + ("Bob", 25), + ("Charlie", 35), + ("O'Neill", 40), + ('O"no', 45), +] + +DEFAULT_SQL_DATA = [ + (1, "Alice", 30), + (2, "Bob", 25), + (3, "Charlie", 35), + (4, "O'Neill", 40), + (5, 'O"no', 45), +] + +INSERT_PRICES_DATA = [ + ("Apple", 1.0), + ("Banana", 2.0), + ("Cherry", 3.0), + ("Durian", 4.0), + ("Elderberry", 5.0), +] + +DEFAULT_PRICES_DATA = [ + (1, "Apple", 1.0), + (2, "Banana", 2.0), + (3, "Cherry", 3.0), + (4, "Durian", 4.0), + (5, "Elderberry", 5.0), +] + + +@contextmanager +def _bootstrap_test_datasources(data_server_cli: "DataServerCliWrapper", tmpdir): + """ + Note: many tests may use the same db name, so we need to ensure that the db is + created with the expected data (even when running in parallel with pytest-xdist). + """ + import time + + from sema4ai_ls_core.basic import wait_for_non_error_condition + + http_port, _mysql_port = data_server_cli.get_http_and_mysql_ports() + + http_connection = None + + def make_connection(): + from sema4ai_code.data.data_server_connection import DataServerConnection + + nonlocal http_connection + curtime = time.time() + http_connection = DataServerConnection( + http_url=f"http://localhost:{http_port}", + http_user=data_server_cli.get_username(), + http_password=data_server_cli.get_password(), + ) + http_connection.login() + print(f"Took {time.time() - curtime:.2f} seconds to connect/login") + + # Bootstrapping it can take a really long time... + wait_for_non_error_condition(make_connection, timeout=60 * 10, sleep=2) + + curtime = time.time() + assert http_connection is not None + result_set = http_connection.query( + "", "select NAME, ENGINE from information_schema.databases where TYPE='data'" + ) + columns = result_set.columns + assert columns[0].lower() == "name" + databases_info = list(result_set.iter_as_tuples()) + print(f"Took {time.time() - curtime:.2f} seconds to list databases") + _create_db_if_needed( + http_connection, + test_db_name, + databases_info, + DEFAULT_SQL_DATA, + create_sqlite_sample_db, + tmpdir, + "user_info", + ) + _create_db_if_needed( + http_connection, + another_test_db_name, + databases_info, + DEFAULT_PRICES_DATA, + create_another_sqlite_sample_db, + tmpdir, + "prices", + ) + + yield http_connection + + +def _create_db_if_needed( + http_connection: "DataServerConnection", + db_name: str, + databases_info: list, + default_data: list, + create_db_fn: Callable[[Path], Path], + tmpdir: Path, + table_name: str, +): + import json + + found_test_db = False + needs_to_create = True + for db in databases_info: + if db[0] == db_name: + found_test_db = True + break + + if found_test_db: + needs_to_create = False + # Check that the existing version has the data we expect. + current_db_data_valid = _is_current_db_data_valid( + http_connection, db_name, default_data, table_name + ) + + if not current_db_data_valid: + http_connection.run_sql(f"DROP DATABASE `{db_name}`") + needs_to_create = True + + if needs_to_create: + params = json.dumps({"db_file": str(create_db_fn(tmpdir))}) + engine = "sqlite" + http_connection.run_sql( + f"CREATE DATABASE `{db_name}` ENGINE = '{engine}' , PARAMETERS = {params}", + ) + + _is_current_db_data_valid( + http_connection, db_name, default_data, table_name, make_assert=True + ) + + +def _is_current_db_data_valid( + http_connection: "DataServerConnection", + db_name: str, + default_data: list, + table_name: str, + make_assert: bool = False, +) -> bool: + try: + result = http_connection.query("", f"SELECT * FROM `{db_name}`.{table_name}") + except Exception: + return False + assert result is not None + rows = list(result.iter_as_tuples()) + + expected = default_data + current_db_data_valid = rows == expected + if make_assert: + assert ( + current_db_data_valid + ), f"Current data is not valid. Found: {rows}. Expected: {expected}" + return current_db_data_valid + + +@pytest.fixture(scope="session") +def data_server_cli(request, tmpdir_factory) -> Iterator["DataServerCliWrapper"]: + from sema4ai_code_tests.data_server_cli_wrapper import DataServerCliWrapper + from sema4ai_ls_core.system_mutex import timed_acquire_mutex + + from sema4ai_code.rcc import RCC_CLOUD_ROBOT_MUTEX_NAME + + wrapper = DataServerCliWrapper(Path(str(tmpdir_factory.mktemp("data-server-cli")))) + # This can be pretty slow (and may be common with pytest-xdist). + with timed_acquire_mutex(RCC_CLOUD_ROBOT_MUTEX_NAME, timeout=60 * 20): + wrapper.download_data_server_cli() + wrapper.start() + + def teardown(): + if request.session.testsfailed: + wrapper.print_log() + + request.addfinalizer(teardown) + + with _bootstrap_test_datasources( + wrapper, tmpdir_factory.mktemp("tmpdir") + ) as http_connection: + wrapper.http_connection = http_connection + yield wrapper + + +test_db_name = "sqlite-test-db" +another_test_db_name = "another-sqlite-test-db" + + +def create_sqlite_sample_db(tmpdir) -> Path: + import sqlite3 + + # Create a sample sqlite db in the tmpdir + db_path = Path(tmpdir.join("sample.db")) + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Create a sample table + cursor.execute( + """ + CREATE TABLE user_info ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + age INTEGER + ) + """ + ) + + # Insert sample data + cursor.executemany( + """ + INSERT INTO user_info (name, age) VALUES (?, ?) + """, + INSERT_SQL_DATA, + ) + + cursor.execute("SELECT * FROM user_info") + result = cursor.fetchall() + assert result == DEFAULT_SQL_DATA + + # Commit changes and close the connection + conn.commit() + conn.close() + + return db_path + + +def create_another_sqlite_sample_db(tmpdir) -> Path: + import sqlite3 + + # Create a sample sqlite db in the tmpdir + db_path = Path(tmpdir.join("another_sample.db")) + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Create a sample table + cursor.execute( + """ + CREATE TABLE prices ( + id INTEGER PRIMARY KEY, + item_name TEXT NOT NULL, + price REAL + ) + """ + ) + + # Insert sample data + cursor.executemany( + """ + INSERT INTO prices (item_name, price) VALUES (?, ?) + """, + INSERT_PRICES_DATA, + ) + + cursor.execute("SELECT * FROM prices") + result = cursor.fetchall() + assert result == DEFAULT_PRICES_DATA + + # Commit changes and close the connection + conn.commit() + conn.close() + + return db_path diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions.py b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions.py index 20aaf5a78..3faa5b9b0 100644 --- a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions.py +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions.py @@ -4,10 +4,32 @@ import pytest from sema4ai_code_tests.protocols import IRobocorpLanguageServerClient from sema4ai_ls_core import uris +from sema4ai_ls_core.protocols import ActionInfoTypedDict, DatasourceInfoTypedDict from sema4ai_code.robo.collect_actions import get_metadata +def test_list_actions_and_datasources_simple(cases, data_regression): + action_package_path = Path(cases.get_path("action_package", must_exist=True)) + + from sema4ai_code.robo.collect_actions_ast import iter_actions_and_datasources + + result = list( + iter_actions_and_datasources(action_package_path, collect_datasources=True) + ) + result = _fix_result(result) + + data_regression.check(result) + + +def _fix_result(result: list[ActionInfoTypedDict | DatasourceInfoTypedDict]): + for entry in result: + entry["uri"] = os.path.basename(entry["uri"]) + + result = sorted(result, key=lambda x: x["name"]) + return result + + def test_list_actions( language_server_initialized: IRobocorpLanguageServerClient, ws_root_path, @@ -28,10 +50,8 @@ def test_list_actions( } ], )["result"]["result"] - for entry in result: - entry["uri"] = os.path.basename(entry["uri"]) + result = _fix_result(result) - result = sorted(result, key=lambda x: x["name"]) data_regression.check(result) @@ -271,6 +291,52 @@ def data_sources() -> str: """ +def data_sources_2() -> str: + return """ +import typing +from sema4ai.data import DataSource, DataSourceSpec + +FileChurnDataSource = typing.Annotated[ + DataSource, + DataSourceSpec( + created_table="churn", + file="files/customer-churn.csv", + engine="files", + description="Datasource which provides a table named 'churn' with customer churn data.", + ), +] + +ChurnPredictionDataSource = typing.Annotated[ + DataSource, + DataSourceSpec( + model_name="customer_churn_predictor", + engine="prediction:lightwood", + description="Datasource which provides along with a table named `customer_churn_predictor`.", + setup_sql="CREATE MODEL IF NOT EXISTS customer_churn_predictor FROM files (SELECT * FROM churn) PREDICT Churn;", + ), +] +""" + + +@pytest.mark.parametrize( + "scenario", + [data_sources, data_sources_2], +) +def test_list_actions_and_datasources_mutiple(data_regression, scenario, tmpdir): + action_package_path = Path(tmpdir) + scenario_path = action_package_path / "data_sources.py" + scenario_path.write_text(scenario(), "utf-8") + + from sema4ai_code.robo.collect_actions_ast import iter_actions_and_datasources + + result = list( + iter_actions_and_datasources(action_package_path, collect_datasources=True) + ) + result = _fix_result(result) + + data_regression.check(result) + + @pytest.mark.parametrize( "scenario", [just_oauth2, multiple_types, just_enum, table_type, complex_type], diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_get_actions_metadata_above_version_complex_type_.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_get_actions_metadata_above_version_complex_type_.yml index a99486aa7..654bbbcfe 100644 --- a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_get_actions_metadata_above_version_complex_type_.yml +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_get_actions_metadata_above_version_complex_type_.yml @@ -20,7 +20,7 @@ actions: class_: default: '' description: The class of the form element - title: 'Class ' + title: Class type: string count: default: 1 diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions.yml index 937cac7f4..68aed407c 100644 --- a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions.yml +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions.yml @@ -3,13 +3,14 @@ kind: datasource model_name: null name: files + python_variable_name: FileChurnDataSource range: end: - character: 5 - line: 12 + character: 19 + line: 5 start: - character: 4 - line: 7 + character: 0 + line: 5 uri: data_sources.py - kind: query name: get_churn_data @@ -26,13 +27,14 @@ kind: datasource model_name: customer_churn_predictor name: models + python_variable_name: ChurnPredictionDataSource range: end: - character: 5 - line: 28 + character: 25 + line: 15 start: - character: 4 - line: 17 + character: 0 + line: 15 uri: data_sources.py - kind: action name: my_action diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources.yml new file mode 100644 index 000000000..937cac7f4 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources.yml @@ -0,0 +1,66 @@ +- created_table: churn + engine: files + kind: datasource + model_name: null + name: files + range: + end: + character: 5 + line: 12 + start: + character: 4 + line: 7 + uri: data_sources.py +- kind: query + name: get_churn_data + range: + end: + character: 18 + line: 8 + start: + character: 4 + line: 8 + uri: data_actions.py +- created_table: null + engine: prediction:lightwood + kind: datasource + model_name: customer_churn_predictor + name: models + range: + end: + character: 5 + line: 28 + start: + character: 4 + line: 17 + uri: data_sources.py +- kind: action + name: my_action + range: + end: + character: 13 + line: 5 + start: + character: 4 + line: 5 + uri: my_action.py +- kind: action + name: my_action_2 + range: + end: + character: 15 + line: 10 + start: + character: 4 + line: 10 + uri: my_action.py +- kind: predict + name: predict_churn + range: + end: + character: 17 + line: 21 + start: + character: 4 + line: 21 + uri: data_actions.py diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_mutiple_data_sources_.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_mutiple_data_sources_.yml new file mode 100644 index 000000000..88f439418 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_mutiple_data_sources_.yml @@ -0,0 +1,28 @@ +- created_table: churn + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: FileChurnDataSource + range: + end: + character: 19 + line: 5 + start: + character: 0 + line: 5 + uri: data_sources.py +- created_table: null + engine: prediction:lightwood + kind: datasource + model_name: customer_churn_predictor + name: models + python_variable_name: ChurnPredictionDataSource + range: + end: + character: 25 + line: 15 + start: + character: 0 + line: 15 + uri: data_sources.py diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_mutiple_data_sources_2_.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_mutiple_data_sources_2_.yml new file mode 100644 index 000000000..88f439418 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_mutiple_data_sources_2_.yml @@ -0,0 +1,28 @@ +- created_table: churn + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: FileChurnDataSource + range: + end: + character: 19 + line: 5 + start: + character: 0 + line: 5 + uri: data_sources.py +- created_table: null + engine: prediction:lightwood + kind: datasource + model_name: customer_churn_predictor + name: models + python_variable_name: ChurnPredictionDataSource + range: + end: + character: 25 + line: 15 + start: + character: 0 + line: 15 + uri: data_sources.py diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_simple.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_simple.yml new file mode 100644 index 000000000..68aed407c --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_and_datasources_simple.yml @@ -0,0 +1,68 @@ +- created_table: churn + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: FileChurnDataSource + range: + end: + character: 19 + line: 5 + start: + character: 0 + line: 5 + uri: data_sources.py +- kind: query + name: get_churn_data + range: + end: + character: 18 + line: 8 + start: + character: 4 + line: 8 + uri: data_actions.py +- created_table: null + engine: prediction:lightwood + kind: datasource + model_name: customer_churn_predictor + name: models + python_variable_name: ChurnPredictionDataSource + range: + end: + character: 25 + line: 15 + start: + character: 0 + line: 15 + uri: data_sources.py +- kind: action + name: my_action + range: + end: + character: 13 + line: 5 + start: + character: 4 + line: 5 + uri: my_action.py +- kind: action + name: my_action_2 + range: + end: + character: 15 + line: 10 + start: + character: 4 + line: 10 + uri: my_action.py +- kind: predict + name: predict_churn + range: + end: + character: 17 + line: 21 + start: + character: 4 + line: 21 + uri: data_actions.py diff --git a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_full_complex_type_.yml b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_full_complex_type_.yml index 2c6ca29cd..e547d2e7f 100644 --- a/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_full_complex_type_.yml +++ b/sema4ai/tests/sema4ai_code_tests/robo/test_list_actions/test_list_actions_full_complex_type_.yml @@ -65,7 +65,7 @@ my_action: class_: default: '' description: The class of the form element - title: 'Class ' + title: Class type: string count: default: 1 diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state.py b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state.py new file mode 100644 index 000000000..1663e1762 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state.py @@ -0,0 +1,135 @@ +import pytest +from sema4ai_code_tests.data_server_cli_wrapper import DataServerCliWrapper +from sema4ai_ls_core.protocols import DataSourceStateDict + + +@pytest.fixture +def cleanup_data_sources(data_server_cli: DataServerCliWrapper): + assert data_server_cli.http_connection is not None + data_server_cli.http_connection.run_sql( + "DROP TABLE IF EXISTS files.customers_in_test_compute_data_sources_state" + ) + data_server_cli.http_connection.run_sql( + "DROP DATABASE IF EXISTS test_compute_data_sources_state" + ) + yield + data_server_cli.http_connection.run_sql( + "DROP TABLE IF EXISTS files.customers_in_test_compute_data_sources_state" + ) + data_server_cli.http_connection.run_sql( + "DROP DATABASE IF EXISTS test_compute_data_sources_state" + ) + + +@pytest.mark.data_server +def test_compute_data_sources_state( + data_server_cli: DataServerCliWrapper, + language_server_initialized, + ws_root_path, + datadir, + data_regression, + cleanup_data_sources, + tmpdir, +): + import json + import shutil + + from sema4ai_code_tests.data_server_fixtures import create_another_sqlite_sample_db + from sema4ai_ls_core import uris + + from sema4ai_code.protocols import DataServerConfigTypedDict + + shutil.copytree(datadir / "package", ws_root_path) + + language_server = language_server_initialized + + http_port, mysql_port = data_server_cli.get_http_and_mysql_ports() + + data_server_info: DataServerConfigTypedDict = { + "api": { + "http": {"host": "localhost", "port": str(http_port)}, + "mysql": { + "host": "localhost", + "port": str(mysql_port), + "ssl": False, + }, + }, + "auth": { + "http_auth_enabled": False, + "password": data_server_cli.get_password(), + "username": data_server_cli.get_username(), + }, + "isRunning": True, + "pid": -1, + "pidFilePath": "", + } + + def collect_data_source_state() -> DataSourceStateDict: + result = language_server.request( + { + "jsonrpc": "2.0", + "id": language_server.next_id(), + "method": "computeDataSourceState", + "params": { + "action_package_yaml_directory_uri": uris.from_fs_path( + ws_root_path + ), + "data_server_info": data_server_info, + }, + } + )["result"] + assert result[ + "success" + ], f"Expected success. Full result: {json.dumps(result, indent=2)}" + + assert result["result"] is not None, "Expected result to be not None" + fixed_result: DataSourceStateDict = fix_data_sources_state_result( + result["result"] + ) + return fixed_result + + fixed_result = collect_data_source_state() + data_regression.check(fixed_result, basename="missing_data_source_all") + + # Now, let's configure the file data source. + assert data_server_cli.http_connection is not None + data_server_cli.http_connection.upload_file( + datadir / "package" / "files" / "customers.csv", + "customers_in_test_compute_data_sources_state", + ) + fixed_result = collect_data_source_state() + data_regression.check(fixed_result, basename="missing_data_source_sqlite") + + params = json.dumps({"db_file": str(create_another_sqlite_sample_db(tmpdir))}) + engine = "sqlite" + data_server_cli.http_connection.run_sql( + f"CREATE DATABASE `test_compute_data_sources_state` ENGINE = '{engine}' , PARAMETERS = {params}", + ) + + fixed_result = collect_data_source_state() + data_regression.check(fixed_result, basename="missing_data_source_none") + + +def fix_data_sources_state_result(result: DataSourceStateDict) -> DataSourceStateDict: + """ + Args: + result: The result to fix (we should change all `uri` to just the basename). + """ + import os.path + + # We don't want existing data sources to affect the test. + result["data_sources_in_data_server"] = [] + + def _fix_uri(obj): + if isinstance(obj, dict): + for key, value in obj.items(): + if key == "uri" and isinstance(value, str): + obj[key] = os.path.basename(value) + elif isinstance(value, (dict, list)): + _fix_uri(value) + elif isinstance(obj, list): + for item in obj: + _fix_uri(item) + + _fix_uri(result) + return result diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_all.yml b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_all.yml new file mode 100644 index 000000000..31f51021b --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_all.yml @@ -0,0 +1,60 @@ +data_sources_in_data_server: [] +required_data_sources: +- created_table: customers_in_test_compute_data_sources_state + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: CustomersDataSource + range: + end: + character: 19 + line: 6 + start: + character: 0 + line: 6 + uri: data_sources.py +- created_table: null + engine: sqlite + kind: datasource + model_name: null + name: test_compute_data_sources_state + python_variable_name: TestSqliteDataSource + range: + end: + character: 20 + line: 17 + start: + character: 0 + line: 17 + uri: data_sources.py +unconfigured_data_sources: +- created_table: customers_in_test_compute_data_sources_state + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: CustomersDataSource + range: + end: + character: 19 + line: 6 + start: + character: 0 + line: 6 + uri: data_sources.py +- created_table: null + engine: sqlite + kind: datasource + model_name: null + name: test_compute_data_sources_state + python_variable_name: TestSqliteDataSource + range: + end: + character: 20 + line: 17 + start: + character: 0 + line: 17 + uri: data_sources.py +uri_to_error_messages: {} diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_none.yml b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_none.yml new file mode 100644 index 000000000..54ffbefdc --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_none.yml @@ -0,0 +1,32 @@ +data_sources_in_data_server: [] +required_data_sources: +- created_table: customers_in_test_compute_data_sources_state + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: CustomersDataSource + range: + end: + character: 19 + line: 6 + start: + character: 0 + line: 6 + uri: data_sources.py +- created_table: null + engine: sqlite + kind: datasource + model_name: null + name: test_compute_data_sources_state + python_variable_name: TestSqliteDataSource + range: + end: + character: 20 + line: 17 + start: + character: 0 + line: 17 + uri: data_sources.py +unconfigured_data_sources: [] +uri_to_error_messages: {} diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_sqlite.yml b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_sqlite.yml new file mode 100644 index 000000000..6d38237e2 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/missing_data_source_sqlite.yml @@ -0,0 +1,46 @@ +data_sources_in_data_server: [] +required_data_sources: +- created_table: customers_in_test_compute_data_sources_state + engine: files + kind: datasource + model_name: null + name: files + python_variable_name: CustomersDataSource + range: + end: + character: 19 + line: 6 + start: + character: 0 + line: 6 + uri: data_sources.py +- created_table: null + engine: sqlite + kind: datasource + model_name: null + name: test_compute_data_sources_state + python_variable_name: TestSqliteDataSource + range: + end: + character: 20 + line: 17 + start: + character: 0 + line: 17 + uri: data_sources.py +unconfigured_data_sources: +- created_table: null + engine: sqlite + kind: datasource + model_name: null + name: test_compute_data_sources_state + python_variable_name: TestSqliteDataSource + range: + end: + character: 20 + line: 17 + start: + character: 0 + line: 17 + uri: data_sources.py +uri_to_error_messages: {} diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/data_actions.py b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/data_actions.py new file mode 100644 index 000000000..fc1ead9c9 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/data_actions.py @@ -0,0 +1,16 @@ +from sema4ai.data import query + +from .data_sources import CustomersDataSource + + +@query +def get_customers_data(customers_data_source: CustomersDataSource) -> str: + """ + Query the customers data + Arguments: + customers_data_source: The datasource to access files/customers.csv file + Returns: + The customers information as a markdown table. + """ + result = customers_data_source.query("SELECT * FROM customers LIMIT 10;") + return result.to_markdown() diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/data_sources.py b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/data_sources.py new file mode 100644 index 000000000..dadbd9746 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/data_sources.py @@ -0,0 +1,24 @@ +from typing import Annotated + +from sema4ai.data import DataSource, DataSourceSpec + +# Generated data source (can be configured automatically) +CustomersDataSource = Annotated[ + DataSource, + DataSourceSpec( + created_table="customers_in_test_compute_data_sources_state", + file="files/customers.csv", + engine="files", + description="Data source for customers.", + ), +] + +# External data source (needs to be configured separately) +TestSqliteDataSource = Annotated[ + DataSource, + DataSourceSpec( + name="test_compute_data_sources_state", + engine="sqlite", + description="Data source for tests.", + ), +] diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/files/customers.csv b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/files/customers.csv new file mode 100644 index 000000000..635248cff --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/files/customers.csv @@ -0,0 +1,101 @@ +Index,Customer Id,First Name,Last Name,Company,City,Country,Phone 1,Phone 2,Email,Subscription Date,Website +1,DD37Cf93aecA6Dc,Sheryl,Baxter,Rasmussen Group,East Leonard,Chile,229.077.5154,397.884.0519x718,zunigavanessa@smith.info,2020-08-24,http://www.stephenson.com/ +2,1Ef7b82A4CAAD10,Preston,Lozano,Vega-Gentry,East Jimmychester,Djibouti,5153435776,686-620-1820x944,vmata@colon.com,2021-04-23,http://www.hobbs.com/ +3,6F94879bDAfE5a6,Roy,Berry,Murillo-Perry,Isabelborough,Antigua and Barbuda,+1-539-402-0259,(496)978-3969x58947,beckycarr@hogan.com,2020-03-25,http://www.lawrence.com/ +4,5Cef8BFA16c5e3c,Linda,Olsen,"Dominguez, Mcmillan and Donovan",Bensonview,Dominican Republic,001-808-617-6467x12895,+1-813-324-8756,stanleyblackwell@benson.org,2020-06-02,http://www.good-lyons.com/ +5,053d585Ab6b3159,Joanna,Bender,"Martin, Lang and Andrade",West Priscilla,Slovakia (Slovak Republic),001-234-203-0635x76146,001-199-446-3860x3486,colinalvarado@miles.net,2021-04-17,https://goodwin-ingram.com/ +6,2d08FB17EE273F4,Aimee,Downs,Steele Group,Chavezborough,Bosnia and Herzegovina,(283)437-3886x88321,999-728-1637,louis27@gilbert.com,2020-02-25,http://www.berger.net/ +7,EA4d384DfDbBf77,Darren,Peck,"Lester, Woodard and Mitchell",Lake Ana,Pitcairn Islands,(496)452-6181x3291,+1-247-266-0963x4995,tgates@cantrell.com,2021-08-24,https://www.le.com/ +8,0e04AFde9f225dE,Brett,Mullen,"Sanford, Davenport and Giles",Kimport,Bulgaria,001-583-352-7197x297,001-333-145-0369,asnow@colon.com,2021-04-12,https://hammond-ramsey.com/ +9,C2dE4dEEc489ae0,Sheryl,Meyers,Browning-Simon,Robersonstad,Cyprus,854-138-4911x5772,+1-448-910-2276x729,mariokhan@ryan-pope.org,2020-01-13,https://www.bullock.net/ +10,8C2811a503C7c5a,Michelle,Gallagher,Beck-Hendrix,Elaineberg,Timor-Leste,739.218.2516x459,001-054-401-0347x617,mdyer@escobar.net,2021-11-08,https://arias.com/ +11,216E205d6eBb815,Carl,Schroeder,"Oconnell, Meza and Everett",Shannonville,Guernsey,637-854-0256x825,114.336.0784x788,kirksalas@webb.com,2021-10-20,https://simmons-hurley.com/ +12,CEDec94deE6d69B,Jenna,Dodson,"Hoffman, Reed and Mcclain",East Andrea,Vietnam,(041)737-3846,+1-556-888-3485x42608,mark42@robbins.com,2020-11-29,http://www.douglas.net/ +13,e35426EbDEceaFF,Tracey,Mata,Graham-Francis,South Joannamouth,Togo,001-949-844-8787,(855)713-8773,alex56@walls.org,2021-12-02,http://www.beck.com/ +14,A08A8aF8BE9FaD4,Kristine,Cox,Carpenter-Cook,Jodyberg,Sri Lanka,786-284-3358x62152,+1-315-627-1796x8074,holdenmiranda@clarke.com,2021-02-08,https://www.brandt.com/ +15,6fEaA1b7cab7B6C,Faith,Lutz,Carter-Hancock,Burchbury,Singapore,(781)861-7180x8306,207-185-3665,cassieparrish@blevins-chapman.net,2022-01-26,http://stevenson.org/ +16,8cad0b4CBceaeec,Miranda,Beasley,Singleton and Sons,Desireeshire,Oman,540.085.3135x185,+1-600-462-6432x21881,vduncan@parks-hardy.com,2022-04-12,http://acosta.org/ +17,a5DC21AE3a21eaA,Caroline,Foley,Winters-Mendoza,West Adriennestad,Western Sahara,936.222.4746x9924,001-469-948-6341x359,holtgwendolyn@watson-davenport.com,2021-03-10,http://www.benson-roth.com/ +18,F8Aa9d6DfcBeeF8,Greg,Mata,Valentine LLC,Lake Leslie,Mozambique,(701)087-2415,(195)156-1861x26241,jaredjuarez@carroll.org,2022-03-26,http://pitts-cherry.com/ +19,F160f5Db3EfE973,Clifford,Jacobson,Simon LLC,Harmonview,South Georgia and the South Sandwich Islands,001-151-330-3524x0469,(748)477-7174,joseph26@jacobson.com,2020-09-24,https://mcconnell.com/ +20,0F60FF3DdCd7aB0,Joanna,Kirk,Mays-Mccormick,Jamesshire,French Polynesia,(266)131-7001x711,(283)312-5579x11543,tuckerangie@salazar.net,2021-09-24,https://www.camacho.net/ +21,9F9AdB7B8A6f7F2,Maxwell,Frye,Patterson Inc,East Carly,Malta,423.262.3059,202-880-0688x7491,fgibson@drake-webb.com,2022-01-12,http://www.roberts.com/ +22,FBd0Ded4F02a742,Kiara,Houston,"Manning, Hester and Arroyo",South Alvin,Netherlands,001-274-040-3582x10611,+1-528-175-0973x4684,blanchardbob@wallace-shannon.com,2020-09-15,https://www.reid-potts.com/ +23,2FB0FAA1d429421,Colleen,Howard,Greer and Sons,Brittanyview,Paraguay,1935085151,(947)115-7711x5488,rsingleton@ryan-cherry.com,2020-08-19,http://paul.biz/ +24,010468dAA11382c,Janet,Valenzuela,Watts-Donaldson,Veronicamouth,Lao People's Democratic Republic,354.259.5062x7538,500.433.2022,stefanie71@spence.com,2020-09-08,https://moreno.biz/ +25,eC1927Ca84E033e,Shane,Wilcox,Tucker LLC,Bryanville,Albania,(429)005-9030x11004,541-116-4501,mariah88@santos.com,2021-04-06,https://www.ramos.com/ +26,09D7D7C8Fe09aea,Marcus,Moody,Giles Ltd,Kaitlyntown,Panama,674-677-8623,909-277-5485x566,donnamullins@norris-barrett.org,2022-05-24,https://www.curry.com/ +27,aBdfcF2c50b0bfD,Dakota,Poole,Simmons Group,Michealshire,Belarus,(371)987-8576x4720,071-152-1376,stacey67@fields.org,2022-02-20,https://sanford-wilcox.biz/ +28,b92EBfdF8a3f0E6,Frederick,Harper,"Hinton, Chaney and Stokes",South Marissatown,Switzerland,+1-077-121-1558x0687,264.742.7149,jacobkhan@bright.biz,2022-05-26,https://callahan.org/ +29,3B5dAAFA41AFa22,Stefanie,Fitzpatrick,Santana-Duran,Acevedoville,Saint Vincent and the Grenadines,(752)776-3286,+1-472-021-4814x85074,wterrell@clark.com,2020-07-30,https://meyers.com/ +30,EDA69ca7a6e96a2,Kent,Bradshaw,Sawyer PLC,North Harold,Tanzania,+1-472-143-5037x884,126.922.6153,qjimenez@boyd.com,2020-04-26,http://maynard-ho.com/ +31,64DCcDFaB9DFd4e,Jack,Tate,"Acosta, Petersen and Morrow",West Samuel,Zimbabwe,965-108-4406x20714,046.906.1442x6784,gfigueroa@boone-zavala.com,2021-09-15,http://www.hawkins-ramsey.com/ +32,679c6c83DD872d6,Tom,Trujillo,Mcgee Group,Cunninghamborough,Denmark,416-338-3758,(775)890-7209,tapiagreg@beard.info,2022-01-13,http://www.daniels-klein.com/ +33,7Ce381e4Afa4ba9,Gabriel,Mejia,Adkins-Salinas,Port Annatown,Liechtenstein,4077245425,646.044.0696x66800,coleolson@jennings.net,2021-04-24,https://patel-hanson.info/ +34,A09AEc6E3bF70eE,Kaitlyn,Santana,Herrera Group,New Kaitlyn,United States of America,6303643286,447-710-6202x07313,georgeross@miles.org,2021-09-21,http://pham.com/ +35,aA9BAFfBc3710fe,Faith,Moon,"Waters, Chase and Aguilar",West Marthaburgh,Bahamas,+1-586-217-0359x6317,+1-818-199-1403,willistonya@randolph-baker.com,2021-11-03,https://spencer-charles.info/ +36,E11dfb2DB8C9f72,Tammie,Haley,"Palmer, Barnes and Houston",East Teresa,Belize,001-276-734-4113x6087,(430)300-8770,harrisisaiah@jenkins.com,2022-01-04,http://evans-simon.com/ +37,889eCf90f68c5Da,Nicholas,Sosa,Jordan Ltd,South Hunter,Uruguay,(661)425-6042,975-998-1519,fwolfe@dorsey.com,2021-08-10,https://www.fleming-richards.com/ +38,7a1Ee69F4fF4B4D,Jordan,Gay,Glover and Sons,South Walter,Solomon Islands,7208417020,8035336772,tiffanydavies@harris-mcfarland.org,2021-02-24,http://www.lee.org/ +39,dca4f1D0A0fc5c9,Bruce,Esparza,Huerta-Mclean,Poolefurt,Montenegro,559-529-4424,001-625-000-7132x0367,preese@frye-vega.com,2021-10-22,http://www.farley.org/ +40,17aD8e2dB3df03D,Sherry,Garza,Anderson Ltd,West John,Poland,001-067-713-6440x158,(978)289-8785x5766,ann48@miller.com,2021-11-01,http://spence.com/ +41,2f79Cd309624Abb,Natalie,Gentry,Monroe PLC,West Darius,Dominican Republic,830.996.8238,499.122.5415,tcummings@fitzpatrick-ashley.com,2020-10-10,http://www.dorsey.biz/ +42,6e5ad5a5e2bB5Ca,Bryan,Dunn,Kaufman and Sons,North Jimstad,Burkina Faso,001-710-802-5565,078.699.8982x13881,woodwardandres@phelps.com,2021-09-08,http://www.butler.com/ +43,7E441b6B228DBcA,Wayne,Simpson,Perkins-Trevino,East Rebekahborough,Bolivia,(344)156-8632x1869,463-445-3702x38463,barbarapittman@holder.com,2020-12-13,https://gillespie-holder.com/ +44,D3fC11A9C235Dc6,Luis,Greer,Cross PLC,North Drew,Bulgaria,001-336-025-6849x701,684.698.2911x6092,bstuart@williamson-mcclure.com,2022-05-15,https://fletcher-nielsen.com/ +45,30Dfa48fe5Ede78,Rhonda,Frost,"Herrera, Shepherd and Underwood",Lake Lindaburgh,Monaco,(127)081-9339,+1-431-028-3337x3492,zkrueger@wolf-chavez.net,2021-12-06,http://www.khan.com/ +46,fD780ED8dbEae7B,Joanne,Montes,"Price, Sexton and Mcdaniel",Gwendolynview,Palau,(897)726-7952,(467)886-9467x5721,juan80@henson.net,2020-07-01,http://ochoa.com/ +47,300A40d3ce24bBA,Geoffrey,Guzman,Short-Wiggins,Zimmermanland,Uzbekistan,975.235.8921x269,(983)188-6873,bauercrystal@gay.com,2020-04-23,https://decker-kline.com/ +48,283DFCD0Dba40aF,Gloria,Mccall,"Brennan, Acosta and Ramos",North Kerriton,Ghana,445-603-6729,001-395-959-4736x4524,bartlettjenna@zuniga-moss.biz,2022-03-11,http://burgess-frank.com/ +49,F4Fc91fEAEad286,Brady,Cohen,Osborne-Erickson,North Eileenville,United Arab Emirates,741.849.0139x524,+1-028-691-7497x0894,mccalltyrone@durham-rose.biz,2022-03-10,http://hammond-barron.com/ +50,80F33Fd2AcebF05,Latoya,Mccann,"Hobbs, Garrett and Sanford",Port Sergiofort,Belarus,(530)287-4548x29481,162-234-0249x32790,bobhammond@barry.biz,2021-12-02,https://www.burton.com/ +51,Aa20BDe68eAb0e9,Gerald,Hawkins,"Phelps, Forbes and Koch",New Alberttown,Canada,+1-323-239-1456x96168,(092)508-0269,uwarner@steele-arias.com,2021-03-19,https://valenzuela.com/ +52,e898eEB1B9FE22b,Samuel,Crawford,"May, Goodwin and Martin",South Jasmine,Algeria,802-242-7457,626.116.9535x8578,xpittman@ritter-carney.net,2021-03-27,https://guerrero.org/ +53,faCEF517ae7D8eB,Patricia,Goodwin,"Christian, Winters and Ellis",Cowanfort,Swaziland,322.549.7139x70040,(111)741-4173,vaughanchristy@lara.biz,2021-03-08,http://clark.info/ +54,c09952De6Cda8aA,Stacie,Richard,Byrd Inc,New Deborah,Madagascar,001-622-948-3641x24810,001-731-168-2893x8891,clinton85@colon-arias.org,2020-10-15,https://kim.com/ +55,f3BEf3Be028166f,Robin,West,"Nixon, Blackwell and Sosa",Wallstown,Ecuador,698.303.4267,001-683-837-7651x525,greenemiranda@zimmerman.com,2022-01-13,https://www.mora.com/ +56,C6F2Fc6a7948a4e,Ralph,Haas,Montes PLC,Lake Ellenchester,Palestinian Territory,2239271999,001-962-434-0867x649,goodmancesar@figueroa.biz,2020-05-25,http://may.com/ +57,c8FE57cBBdCDcb2,Phyllis,Maldonado,Costa PLC,Lake Whitney,Saint Barthelemy,4500370767,001-508-064-6725x017,yhanson@warner-diaz.org,2021-01-25,http://www.bernard.com/ +58,B5acdFC982124F2,Danny,Parrish,Novak LLC,East Jaredbury,United Arab Emirates,(669)384-8597x8794,506.731.5952x571,howelldarren@house-cohen.com,2021-03-17,http://www.parsons-hudson.com/ +59,8c7DdF10798bCC3,Kathy,Hill,"Moore, Mccoy and Glass",Selenabury,South Georgia and the South Sandwich Islands,001-171-716-2175x310,888.625.0654,ncamacho@boone-simmons.org,2020-11-15,http://hayden.com/ +60,C681dDd0cc422f7,Kelli,Hardy,Petty Ltd,Huangfort,Sao Tome and Principe,020.324.2191x2022,424-157-8216,kristopher62@oliver.com,2020-12-20,http://www.kidd.com/ +61,a940cE42e035F28,Lynn,Pham,"Brennan, Camacho and Tapia",East Pennyshire,Portugal,846.468.6834x611,001-248-691-0006,mpham@rios-guzman.com,2020-08-21,https://www.murphy.com/ +62,9Cf5E6AFE0aeBfd,Shelley,Harris,"Prince, Malone and Pugh",Port Jasminborough,Togo,423.098.0315x8373,+1-386-458-8944x15194,zachary96@mitchell-bryant.org,2020-12-10,https://www.ryan.com/ +63,aEcbe5365BbC67D,Eddie,Jimenez,Caldwell Group,West Kristine,Ethiopia,+1-235-657-1073x6306,(026)401-7353x2417,kristiwhitney@bernard.com,2022-03-24,http://cherry.com/ +64,FCBdfCEAe20A8Dc,Chloe,Hutchinson,Simon LLC,South Julia,Netherlands,981-544-9452,+1-288-552-4666x060,leah85@sutton-terrell.com,2022-05-15,https://mitchell.info/ +65,636cBF0835E10ff,Eileen,Lynch,"Knight, Abbott and Hubbard",Helenborough,Liberia,+1-158-951-4131x53578,001-673-779-6713x680,levigiles@vincent.com,2021-01-02,http://mckay.com/ +66,fF1b6c9E8Fbf1ff,Fernando,Lambert,Church-Banks,Lake Nancy,Lithuania,497.829.9038,3863743398,fisherlinda@schaefer.net,2021-04-23,https://www.vang.com/ +67,2A13F74EAa7DA6c,Makayla,Cannon,Henderson Inc,Georgeport,New Caledonia,001-215-801-6392x46009,027-609-6460,scottcurtis@hurley.biz,2020-01-20,http://www.velazquez.net/ +68,a014Ec1b9FccC1E,Tom,Alvarado,Donaldson-Dougherty,South Sophiaberg,Kiribati,(585)606-2980x2258,730-797-3594x5614,nicholsonnina@montgomery.info,2020-08-18,http://odom-massey.com/ +69,421a109cABDf5fa,Virginia,Dudley,Warren Ltd,Hartbury,French Southern Territories,027.846.3705x14184,+1-439-171-1846x4636,zvalencia@phelps.com,2021-01-31,http://hunter-esparza.com/ +70,CC68FD1D3Bbbf22,Riley,Good,Wade PLC,Erikaville,Canada,6977745822,855-436-7641,alex06@galloway.com,2020-02-03,http://conway.org/ +71,CBCd2Ac8E3eBDF9,Alexandria,Buck,Keller-Coffey,Nicolasfort,Iran,078-900-4760x76668,414-112-8700x68751,lee48@manning.com,2021-02-20,https://ramsey.org/ +72,Ef859092FbEcC07,Richard,Roth,Conway-Mcbride,New Jasmineshire,Morocco,581-440-6539,9857827463,aharper@maddox-townsend.org,2020-02-23,https://www.brooks.com/ +73,F560f2d3cDFb618,Candice,Keller,Huynh and Sons,East Summerstad,Zimbabwe,001-927-965-8550x92406,001-243-038-4271x53076,buckleycory@odonnell.net,2020-08-22,https://www.lucero.com/ +74,A3F76Be153Df4a3,Anita,Benson,Parrish Ltd,Skinnerport,Russian Federation,874.617.5668x69878,(399)820-6418x0071,angie04@oconnell.com,2020-02-09,http://oconnor.com/ +75,D01Af0AF7cBbFeA,Regina,Stein,Guzman-Brown,Raystad,Solomon Islands,001-469-848-0724x4407,001-085-360-4426x00357,zrosario@rojas-hardin.net,2022-01-15,http://www.johnston.info/ +76,d40e89dCade7b2F,Debra,Riddle,"Chang, Aguirre and Leblanc",Colinhaven,United States Virgin Islands,+1-768-182-6014x14336,(303)961-4491,shieldskerry@robles.com,2020-07-11,http://kaiser.info/ +77,BF6a1f9bd1bf8DE,Brittany,Zuniga,Mason-Hester,West Reginald,Kyrgyz Republic,(050)136-9025,001-480-851-2496x0157,mchandler@cochran-huerta.org,2021-07-24,http://www.boyle.com/ +78,FfaeFFbbbf280db,Cassidy,Mcmahon,"Mcguire, Huynh and Hopkins",Lake Sherryborough,Myanmar,5040771311,684-682-0021x1326,katrinalane@fitzgerald.com,2020-10-21,https://hurst.com/ +79,CbAE1d1e9a8dCb1,Laurie,Pennington,"Sanchez, Marsh and Hale",Port Katherineville,Dominica,007.155.3406x553,+1-809-862-5566x277,cookejill@powell.com,2020-06-08,http://www.hebert.com/ +80,A7F85c1DE4dB87f,Alejandro,Blair,"Combs, Waller and Durham",Thomasland,Iceland,(690)068-4641x51468,555.509.8691x2329,elizabethbarr@ewing.com,2020-09-19,https://mercado-blevins.com/ +81,D6CEAfb3BDbaa1A,Leslie,Jennings,Blankenship-Arias,Coreybury,Micronesia,629.198.6346,075.256.0829,corey75@wiggins.com,2021-11-13,https://www.juarez.com/ +82,Ebdb6F6F7c90b69,Kathleen,Mckay,"Coffey, Lamb and Johnson",Lake Janiceton,Saint Vincent and the Grenadines,(733)910-9968,(691)247-4128x0665,chloelester@higgins-wilkinson.com,2021-09-12,http://www.owens-mooney.com/ +83,E8E7e8Cfe516ef0,Hunter,Moreno,Fitzpatrick-Lawrence,East Clinton,Isle of Man,(733)833-6754,001-761-013-7121,isaac26@benton-finley.com,2020-12-28,http://walls.info/ +84,78C06E9b6B3DF20,Chad,Davidson,Garcia-Jimenez,South Joshuashire,Oman,8275702958,(804)842-4715,justinwalters@jimenez.com,2021-11-15,http://www.garner-oliver.com/ +85,03A1E62ADdeb31c,Corey,Holt,"Mcdonald, Bird and Ramirez",New Glenda,Fiji,001-439-242-4986x7918,3162708934,maurice46@morgan.com,2020-02-18,http://www.watson.com/ +86,C6763c99d0bd16D,Emma,Cunningham,Stephens Inc,North Jillianview,New Zealand,128-059-0206x60217,(312)164-4545x2284,walter83@juarez.org,2022-05-13,http://www.reid.info/ +87,ebe77E5Bf9476CE,Duane,Woods,Montoya-Miller,Lyonsberg,Maldives,(636)544-7783x7288,(203)287-1003x5932,kmercer@wagner.com,2020-07-21,http://murray.org/ +88,E4Bbcd8AD81fC5f,Alison,Vargas,"Vaughn, Watts and Leach",East Cristinabury,Benin,365-273-8144,053-308-7653x6287,vcantu@norton.com,2020-11-10,http://mason.info/ +89,efeb73245CDf1fF,Vernon,Kane,Carter-Strickland,Thomasfurt,Yemen,114-854-1159x555,499-608-4612,hilljesse@barrett.info,2021-04-15,http://www.duffy-hensley.net/ +90,37Ec4B395641c1E,Lori,Flowers,Decker-Mcknight,North Joeburgh,Namibia,679.415.1210,945-842-3659x4581,tyrone77@valenzuela.info,2021-01-09,http://www.deleon-crosby.com/ +91,5ef6d3eefdD43bE,Nina,Chavez,Byrd-Campbell,Cassidychester,Bhutan,053-344-3205,+1-330-920-5422x571,elliserica@frank.com,2020-03-26,https://www.pugh.com/ +92,98b3aeDcC3B9FF3,Shane,Foley,Rocha-Hart,South Dannymouth,Hungary,+1-822-569-0302,001-626-114-5844x55073,nsteele@sparks.com,2021-07-06,https://www.holt-sparks.com/ +93,aAb6AFc7AfD0fF3,Collin,Ayers,Lamb-Peterson,South Lonnie,Anguilla,404-645-5351x012,001-257-582-8850x8516,dudleyemily@gonzales.biz,2021-06-29,http://www.ruiz.com/ +94,54B5B5Fe9F1B6C5,Sherry,Young,"Lee, Lucero and Johnson",Frankchester,Solomon Islands,158-687-1764,(438)375-6207x003,alan79@gates-mclaughlin.com,2021-04-04,https://travis.net/ +95,BE91A0bdcA49Bbc,Darrell,Douglas,"Newton, Petersen and Mathis",Daisyborough,Mali,001-084-845-9524x1777,001-769-564-6303,grayjean@lowery-good.com,2022-02-17,https://banks.biz/ +96,cb8E23e48d22Eae,Karl,Greer,Carey LLC,East Richard,Guyana,(188)169-1674x58692,001-841-293-3519x614,hhart@jensen.com,2022-01-30,http://hayes-perez.com/ +97,CeD220bdAaCfaDf,Lynn,Atkinson,"Ware, Burns and Oneal",New Bradview,Sri Lanka,+1-846-706-2218,605.413.3198,vkemp@ferrell.com,2021-07-10,https://novak-allison.com/ +98,28CDbC0dFe4b1Db,Fred,Guerra,Schmitt-Jones,Ortegaland,Solomon Islands,+1-753-067-8419x7170,+1-632-666-7507x92121,swagner@kane.org,2021-09-18,https://www.ross.com/ +99,c23d1D9EE8DEB0A,Yvonne,Farmer,Fitzgerald-Harrell,Lake Elijahview,Aruba,(530)311-9786,001-869-452-0943x12424,mccarthystephen@horn-green.biz,2021-08-11,http://watkins.info/ +100,2354a0E336A91A1,Clarence,Haynes,"Le, Nash and Cross",Judymouth,Honduras,(753)813-6941,783.639.1472,colleen91@faulkner.biz,2020-03-11,http://www.hatfield-saunders.net/ diff --git a/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/package.yaml b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/package.yaml new file mode 100644 index 000000000..a8d457ec5 --- /dev/null +++ b/sema4ai/tests/sema4ai_code_tests/test_compute_data_sources_state/package/package.yaml @@ -0,0 +1,31 @@ +# Required: Defines the name of the action package. +name: My awesome cookie maker + +# Required: A description of what's in the action package. +description: This does cookies + +# Package version number, recommend using semver.org +version: 0.0.5 + +dependencies: + conda-forge: + - python=3.10.14 + - uv=0.4.17 + pypi: + - sema4ai-actions=1.1.4 + - sema4ai-data=0.0.3 + +packaging: + # By default, all files and folders in this directory are packaged when uploaded. + # Add exclusion rules below (expects glob format: https://docs.python.org/3/library/glob.html) + exclude: + - ./tests/** # tests don't need to be packaged + - ./.git/** + - ./.vscode/** + - ./devdata/** + - ./output/** + - ./venv/** + - ./.venv/** + - ./.DS_store/** + - ./**/*.pyc + - ./**/*.zip \ No newline at end of file diff --git a/sema4ai/tests/sema4ai_code_tests/test_data_sources_available.py b/sema4ai/tests/sema4ai_code_tests/test_data_sources_available.py new file mode 100644 index 000000000..e69de29bb diff --git a/sema4ai/vscode-client/src/common.ts b/sema4ai/vscode-client/src/common.ts index f70a817b8..1661911b2 100644 --- a/sema4ai/vscode-client/src/common.ts +++ b/sema4ai/vscode-client/src/common.ts @@ -2,7 +2,7 @@ import * as roboCommands from "./robocorpCommands"; import * as vscode from "vscode"; import { commands, FileType, Uri, window, WorkspaceFolder } from "vscode"; import { ActionResult, LocalPackageMetadataInfo, PackageType, PackageYamlName } from "./protocols"; -import { logError } from "./channel"; +import { logError, OUTPUT_CHANNEL } from "./channel"; import { feedbackRobocorpCodeError } from "./rcc"; import { join } from "path"; import { uriExists } from "./files"; @@ -347,3 +347,13 @@ export function compareVersions(version1: string, version2: string): number { return 0; } + +export async function showErrorMessageWithShowOutputButton(message: string) { + const result = await window.showErrorMessage( + message + " (see `OUTPUT > Sema4.ai` for more details).", + "Open OUTPUT > Sema4.ai" + ); + if (result === "Open OUTPUT > Sema4.ai") { + OUTPUT_CHANNEL.show(); + } +} diff --git a/sema4ai/vscode-client/src/dataExtension.ts b/sema4ai/vscode-client/src/dataExtension.ts index b92a0e848..e51318d6b 100644 --- a/sema4ai/vscode-client/src/dataExtension.ts +++ b/sema4ai/vscode-client/src/dataExtension.ts @@ -31,28 +31,32 @@ export async function verifyDataExtensionIsInstalled( if (isDataExtensionInstalled()) { try { let extension = extensions.getExtension(DATA_EXTENSION_ID); - let version = extension?.packageJSON.version; - if (version) { - // If we have a '-' in the version, remove it and everything after it - if (version.includes("-")) { - version = version.split("-")[0]; + if (extension) { + let version = extension?.packageJSON.version; + if (version) { + // If we have a '-' in the version, remove it and everything after it + if (version.includes("-")) { + version = version.split("-")[0]; + } } - } - // Check if version matches something as .. - if (version && version.match(/^\d+\.\d+\.\d+$/)) { - // Check if the version is greater or equal to 1.0.2 (use regexp to extract the version number) - let [major, minor, patch] = version.split(".").map(Number); - if (major > 1 || (major == 1 && minor > 0) || (major == 1 && minor == 0 && patch >= 2)) { - return true; + // Check if version matches something as .. + if (version && version.match(/^\d+\.\d+\.\d+$/)) { + // Check if the version is greater or equal to 1.0.2 (use regexp to extract the version number) + let [major, minor, patch] = version.split(".").map(Number); + if (major > 1 || (major == 1 && minor > 0) || (major == 1 && minor == 0 && patch >= 4)) { + if (!extension?.isActive) { + await extension?.activate(); + } + return true; + } } + // Notify users that the version is too old (or it didn't match the regexp) + window.showWarningMessage( + `The Sema4AI data extension is installed, but the version (${version}) is too old (minimum required version is 1.0.2). Please update it.` + ); + commands.executeCommand("workbench.extensions.search", DATA_EXTENSION_ID); + return false; } - - // Notify users that the version is too old (or it didn't match the regexp) - window.showWarningMessage( - `The Sema4AI data extension is installed, but the version (${version}) is too old (minimum required version is 1.0.2). Please update it.` - ); - commands.executeCommand("workbench.extensions.search", DATA_EXTENSION_ID); - return false; } catch (error) { logError("Error checking data extension version", error, "ERR_CHECK_DATA_EXTENSION_VERSION"); return false; diff --git a/sema4ai/vscode-client/src/extension.ts b/sema4ai/vscode-client/src/extension.ts index f392be9d9..28f6afbfc 100644 --- a/sema4ai/vscode-client/src/extension.ts +++ b/sema4ai/vscode-client/src/extension.ts @@ -162,8 +162,6 @@ import { SEMA4AI_RUN_ACTION_PACKAGE_DEV_TASK, SEMA4AI_CONFIGURE_ACTION_INPUT, SEMA4AI_GET_ACTIONS_METADATA, - SEMA4AI_START_DATA_SERVER, - SEMA4AI_STOP_DATA_SERVER, } from "./robocorpCommands"; import { installWorkspaceWatcher } from "./pythonExtIntegration"; import { refreshCloudTreeView } from "./viewsRobocorp"; @@ -204,11 +202,6 @@ import { getSema4AIStudioURLForAgentZipPath, getSema4AIStudioURLForFolderPath } import { LocalPackageMetadataInfo } from "./protocols"; import { importActionPackage } from "./robo/importActions"; import { DevTaskInfo, runActionPackageDevTask } from "./robo/runActionPackageDevTask"; -import { - DATA_SERVER_START_COMMAND_ID, - DATA_SERVER_STOP_COMMAND_ID, - verifyDataExtensionIsInstalled, -} from "./dataExtension"; interface InterpreterInfo { pythonExe: string; @@ -527,16 +520,6 @@ function registerRobocorpCodeCommands(C: CommandRegistry, context: ExtensionCont runActionPackageDevTask(devTaskInfo) ); C.register(SEMA4AI_GET_ACTIONS_METADATA, getActionsMetadata); - C.register(SEMA4AI_START_DATA_SERVER, async () => { - if (await verifyDataExtensionIsInstalled()) { - await commands.executeCommand(DATA_SERVER_START_COMMAND_ID); - } - }); - C.register(SEMA4AI_STOP_DATA_SERVER, async () => { - if (await verifyDataExtensionIsInstalled()) { - await commands.executeCommand(DATA_SERVER_STOP_COMMAND_ID); - } - }); } async function clearEnvAndRestart() { diff --git a/sema4ai/vscode-client/src/protocols.ts b/sema4ai/vscode-client/src/protocols.ts index cf074cb44..9b3db52c9 100644 --- a/sema4ai/vscode-client/src/protocols.ts +++ b/sema4ai/vscode-client/src/protocols.ts @@ -1,3 +1,5 @@ +import { Diagnostic, DiagnosticSeverity } from "vscode"; + export enum PackageType { Task = "task", Action = "action", @@ -194,3 +196,26 @@ export interface ActionServerPackageUploadStatusOutput { message: string; }; } + +export interface DatasourceInfo { + range: Range; + name: string; + uri: string; + kind: "datasource"; + engine: string; + model_name?: string; + created_table?: string; +} + +export interface DiagnosticInfo { + range: Range; + severity: DiagnosticSeverity; + message: string; +} + +export interface DataSourceState { + unconfigured_data_sources: DatasourceInfo[]; + uri_to_error_messages: { [uri: string]: DiagnosticInfo[] }; + required_data_sources: DatasourceInfo[]; + data_sources_in_data_server: string[]; +} diff --git a/sema4ai/vscode-client/src/rcc.ts b/sema4ai/vscode-client/src/rcc.ts index 0bf8c8481..e85a2164c 100644 --- a/sema4ai/vscode-client/src/rcc.ts +++ b/sema4ai/vscode-client/src/rcc.ts @@ -156,9 +156,9 @@ async function downloadRcc( // Note: python tests scan this file and get these constants, so, if the format // changes the (failing) test also needs to change. -const BASENAME_PREBUILT_WIN_AMD64 = "ffb5eee1a191f326_windows_amd64.zip"; -const BASENAME_PREBUILT_DARWIN = "3b0e7686450769fe_darwin_amd64.zip"; -const BASENAME_PREBUILT_LINUX_AMD64 = "def1f9df7f786b9e_linux_amd64.zip"; +const BASENAME_PREBUILT_WIN_AMD64 = "0ae698fa04c74035_windows_amd64.zip"; +const BASENAME_PREBUILT_DARWIN = "03224defd2ad9de9_darwin_amd64.zip"; +const BASENAME_PREBUILT_LINUX_AMD64 = "a0b7a21132034510_linux_amd64.zip"; function getBaseAsZipBasename() { let basename: string; diff --git a/sema4ai/vscode-client/src/robo/actionPackage.ts b/sema4ai/vscode-client/src/robo/actionPackage.ts index 5413d6728..2ec25c951 100644 --- a/sema4ai/vscode-client/src/robo/actionPackage.ts +++ b/sema4ai/vscode-client/src/robo/actionPackage.ts @@ -23,6 +23,8 @@ import { ActionServerPackageUploadStatusOutput, PackageYamlName, PackageType, + DataSourceState, + DatasourceInfo, } from "../protocols"; import { getPackageName, @@ -37,6 +39,7 @@ import { isAgentPackage, ActionPackageTargetInfo, revealInExtension, + showErrorMessageWithShowOutputButton, } from "../common"; import { slugify } from "../slugify"; import { fileExists, makeDirs, readFromFile, writeToFile } from "../files"; @@ -333,7 +336,29 @@ export async function getTargetInputJson(actionName: string, actionPackageYamlDi return targetInput; } -function convertDataServerInfoToEnvVar(dataServerInfo: any): string { +export interface DataServerConfig { + api: { + http: { + host: string; + port: string; + }; + mysql: { + host: string; + port: string; + ssl: boolean; + }; + }; + auth: { + http_auth_enabled: boolean; + password: string; + username: string; + }; + isRunning: boolean; + pid: number; + pidFilePath: string; +} + +function convertDataServerInfoToEnvVar(dataServerInfo: DataServerConfig): string { // We have something like this: // We have something as: // api: { @@ -342,7 +367,6 @@ function convertDataServerInfoToEnvVar(dataServerInfo: any): string { // port: "47334", // }, // mysql: { - // database: "mindsdb", // host: "127.0.0.1", // port: "47335", // ssl: false, @@ -371,6 +395,45 @@ function convertDataServerInfoToEnvVar(dataServerInfo: any): string { }); } +export function getDataSourceCaption(dataSource: DatasourceInfo): string { + if (dataSource.created_table && dataSource.model_name) { + return `Bad datasource: ${dataSource.name} - created_table: ${dataSource.created_table} and model_name: ${dataSource.model_name} (${dataSource.engine})`; + } + if (dataSource.created_table) { + if (dataSource.engine === "files" || dataSource.engine === "custom") { + return `${dataSource.name}.${dataSource.created_table} (${dataSource.engine})`; + } + return `Bad datasource: ${dataSource.name} - created_table: ${dataSource.created_table} (${dataSource.engine}) - created_table is only expected in 'files' and 'custom' engines`; + } + if (dataSource.model_name) { + if (dataSource.engine.startsWith("prediction") || dataSource.engine === "custom") { + return `${dataSource.name}.${dataSource.model_name} (${dataSource.engine})`; + } + return `Bad datasource: ${dataSource.name} - model_name: ${dataSource.model_name} (${dataSource.engine}) - model_name is only expected in 'prediction' and 'custom' engines`; + } + + // Created table is expected for files engine + if (dataSource.engine === "files") { + return `Bad datasource: ${dataSource.name} (${dataSource.engine}) - expected created_table to be defined`; + } + // Model name is expected for prediction engines + if (dataSource.engine.startsWith("prediction")) { + return `Bad datasource: ${dataSource.name} (${dataSource.engine}) - expected model_name to be defined`; + } + return `${dataSource.name} (${dataSource.engine})`; +} + +async function computeDataSourceState( + actionPackageYamlDirectoryUri: string, + dataServerInfo: DataServerConfig +): Promise> { + const dataSourceState = (await langServer.sendRequest("computeDataSourceState", { + "action_package_yaml_directory_uri": actionPackageYamlDirectoryUri, + "data_server_info": dataServerInfo, + })) as ActionResult; + return dataSourceState; +} + export async function runActionFromActionPackage( noDebug: boolean, actionName: string, @@ -497,7 +560,7 @@ advised to regenerate it as it may not work with future versions of the extensio let result = await window.withProgress( { location: vscode.ProgressLocation.Window, - title: "Getting local data server connection info", + title: "Getting local data server connection info and validating data sources", cancellable: false, }, async ( @@ -511,27 +574,62 @@ advised to regenerate it as it may not work with future versions of the extensio progress.report({ message: "Waiting for data server info... ", }); - const dataServerInfo = await commands.executeCommand(DATA_SERVER_START_COMMAND_ID, { + const dataServerInfo = (await commands.executeCommand(DATA_SERVER_START_COMMAND_ID, { "showUIMessages": false, + })) as DataServerConfig | undefined; + if (!dataServerInfo) { + window.showErrorMessage( + "Unable to run (error getting local data server connection info and validating data sources):\n" + + JSON.stringify(dataServerInfo, null, 4) + ); + return false; + } + + try { + baseEnv["SEMA4AI_DATA_SERVER_INFO"] = convertDataServerInfoToEnvVar(dataServerInfo); + } catch (error) { + window.showErrorMessage( + "Unable to run (error converting data server info to env var):\n" + + JSON.stringify(error, null, 4) + ); + return false; + } + + progress.report({ + message: "Validating data sources... ", }); - if (dataServerInfo) { - try { - baseEnv["SEMA4AI_DATA_SERVER_INFO"] = convertDataServerInfoToEnvVar(dataServerInfo); - return true; - } catch (error) { - window.showErrorMessage( - "Unable to run (error converting data server info to env var):\n" + - JSON.stringify(error, null, 4) - ); - return false; + + // Ok, now, let's verify that the data sources are available. + const dataSourceStateResult = await computeDataSourceState( + vscode.Uri.file(actionPackageYamlDirectory).toString(), + dataServerInfo + ); + if (!dataSourceStateResult.success) { + showErrorMessageWithShowOutputButton(dataSourceStateResult.message); + return false; + } + const dataSourceState = dataSourceStateResult.result; + // Check error messages + if (Object.keys(dataSourceState.uri_to_error_messages).length > 0) { + for (const errorMessages of Object.values(dataSourceState.uri_to_error_messages)) { + for (const errorMessage of errorMessages) { + window.showErrorMessage(errorMessage.message); + } } - } else { + return false; + } + // Check unconfigured data sources + if (dataSourceState.unconfigured_data_sources.length > 0) { window.showErrorMessage( - "Unable to run (error getting local data server connection info):\n" + - JSON.stringify(dataServerInfo, null, 4) + "Unable to run because the following data sources are not configured in the local data server (please configure them and retry):\n" + + dataSourceState.unconfigured_data_sources + .map((ds) => getDataSourceCaption(ds)) + .join(", ") ); return false; } + + return true; } ); if (!result) { diff --git a/sema4ai/vscode-client/src/robocorpCommands.ts b/sema4ai/vscode-client/src/robocorpCommands.ts index a5c6c247f..8504eda92 100644 --- a/sema4ai/vscode-client/src/robocorpCommands.ts +++ b/sema4ai/vscode-client/src/robocorpCommands.ts @@ -145,6 +145,4 @@ export const SEMA4AI_UPDATE_AGENT_VERSION_INTERNAL = "sema4ai.updateAgentVersion export const SEMA4AI_COLLAPSE_ALL_ENTRIES = "sema4ai.collapseAllEntries"; // Collapse All Entries export const SEMA4AI_IMPORT_ACTION_PACKAGE = "sema4ai.importActionPackage"; // Import Action Package export const SEMA4AI_RUN_ACTION_PACKAGE_DEV_TASK = "sema4ai.runActionPackageDevTask"; // Run dev-task (from Action Package) -export const SEMA4AI_GET_ACTIONS_METADATA = "sema4ai.getActionsMetadata"; // Get Actions Metadata -export const SEMA4AI_START_DATA_SERVER = "sema4ai.startDataServer"; // Start Data Server -export const SEMA4AI_STOP_DATA_SERVER = "sema4ai.stopDataServer"; // Stop Data Server \ No newline at end of file +export const SEMA4AI_GET_ACTIONS_METADATA = "sema4ai.getActionsMetadata"; // Get Actions Metadata \ No newline at end of file diff --git a/sema4ai/vscode-client/src/viewsRobots.ts b/sema4ai/vscode-client/src/viewsRobots.ts index cfad712ef..dd9c79e43 100644 --- a/sema4ai/vscode-client/src/viewsRobots.ts +++ b/sema4ai/vscode-client/src/viewsRobots.ts @@ -7,6 +7,7 @@ import { basename, RobotEntry, RobotEntryType } from "./viewsCommon"; import { getSelectedRobot } from "./viewsSelection"; import { isActionPackage, isAgentPackage } from "./common"; import path = require("path"); +import { getDataSourceCaption } from "./robo/actionPackage"; let _globalSentMetric: boolean = false; @@ -520,21 +521,7 @@ export class RobotsTreeDataProvider implements vscode.TreeDataProvider