From 7269eaf22a1b5c13f566ff851c444614bff61f64 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 24 Feb 2025 20:14:26 +0100 Subject: [PATCH] Adding upstream version 1.1.0. Signed-off-by: Daniel Baumann --- .github/workflows/publish.yml | 47 + .github/workflows/release.yml | 57 + .gitignore | 161 +++ .harlequin.toml | 10 + CHANGELOG.md | 79 ++ LICENSE | 21 + Makefile | 18 + README.md | 67 ++ docker-compose.yml | 9 + poetry.lock | 1483 +++++++++++++++++++++++++++ pyproject.toml | 67 ++ src/harlequin_mysql/__init__.py | 3 + src/harlequin_mysql/adapter.py | 428 ++++++++ src/harlequin_mysql/catalog.py | 154 +++ src/harlequin_mysql/cli_options.py | 151 +++ src/harlequin_mysql/completions.py | 48 + src/harlequin_mysql/functions.tsv | 441 ++++++++ src/harlequin_mysql/interactions.py | 113 ++ src/harlequin_mysql/keywords.csv | 892 ++++++++++++++++ src/harlequin_mysql/py.typed | 0 tests/conftest.py | 43 + tests/test_adapter.py | 220 ++++ tests/test_catalog.py | 85 ++ 23 files changed, 4597 insertions(+) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .harlequin.toml create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 src/harlequin_mysql/__init__.py create mode 100644 src/harlequin_mysql/adapter.py create mode 100644 src/harlequin_mysql/catalog.py create mode 100644 src/harlequin_mysql/cli_options.py create mode 100644 src/harlequin_mysql/completions.py create mode 100644 src/harlequin_mysql/functions.tsv create mode 100644 src/harlequin_mysql/interactions.py create mode 100644 src/harlequin_mysql/keywords.csv create mode 100644 src/harlequin_mysql/py.typed create mode 100644 tests/conftest.py create mode 100644 tests/test_adapter.py create mode 100644 tests/test_catalog.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..8405b1a --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,47 @@ +name: Build and Publish Package + +on: + pull_request: + branches: + - main + types: + - closed + +jobs: + publish-package: + if: ${{ github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v') }} + runs-on: ubuntu-latest + + steps: + - name: Check out the main branch + uses: actions/checkout@v4 + with: + ref: main + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.6.1 + - name: Configure poetry + run: poetry config --no-interaction pypi-token.pypi ${{ secrets.PYPI_TOKEN }} + - name: Get this package's Version + id: package_version + run: echo "package_version=$(poetry version --short)" >> $GITHUB_OUTPUT + - name: Build package + run: poetry build --no-interaction + - name: Publish package to PyPI + run: poetry publish --no-interaction + - name: Create a Github Release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ steps.package_version.outputs.package_version }} + target_commitish: main + token: ${{ secrets.GH_RELEASE_TOKEN }} + body_path: CHANGELOG.md + files: | + LICENSE + dist/*harlequin*.whl + dist/*harlequin*.tar.gz diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..213324f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,57 @@ +name: Create Release Branch + +on: + workflow_dispatch: + inputs: + newVersion: + description: A version number for this release (e.g., "0.1.0") + required: true + +jobs: + prepare-release: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Check out the main branch + uses: actions/checkout@v4 + with: + ref: main + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.6.1 + - name: Create release branch + run: | + git checkout -b release/v${{ github.event.inputs.newVersion }} + git push --set-upstream origin release/v${{ github.event.inputs.newVersion }} + - name: Bump version + run: poetry version ${{ github.event.inputs.newVersion }} --no-interaction + - name: Ensure package can be built + run: poetry build --no-interaction + - name: Update CHANGELOG + uses: thomaseizinger/keep-a-changelog-new-release@v1 + with: + version: ${{ github.event.inputs.newVersion }} + - name: Commit Changes + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Bumps version to ${{ github.event.inputs.newVersion }} + - name: Create pull request into main + uses: thomaseizinger/create-pull-request@1.3.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + head: release/v${{ github.event.inputs.newVersion }} + base: main + title: v${{ github.event.inputs.newVersion }} + body: > + This PR was automatically generated. It bumps the version number + in pyproject.toml and updates CHANGELOG.md. You may have to close + this PR and reopen it to get the required checks to run. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..279413a --- /dev/null +++ b/.gitignore @@ -0,0 +1,161 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +Pipfile +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/.harlequin.toml b/.harlequin.toml new file mode 100644 index 0000000..a284631 --- /dev/null +++ b/.harlequin.toml @@ -0,0 +1,10 @@ +default_profile = "azure" +[profiles.azure] +adapter = "mysql" +theme = "harlequin" +limit = 10000 +host = "harlequin-mysql-dev.mysql.database.azure.com" +port = "3306" +database = "dev" +user = "harlequin" +password = "roEj5cN9Jdyqbyqf" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0bf52e6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,79 @@ +# harlequin-mysql CHANGELOG + +All notable changes to this project will be documented in this file. + +## [Unreleased] + +## [1.1.0] - 2025-01-28 + +- Bumps the MySQL Connector Python version to >=9.1 +- Bumps the required Harlequin version to >= 1.25.0 +- Adds support for the `openid_token_file` connection option introduced with MySQL Connector 9.1 +- This adapter now lazy-loads the catalog, which will dramatically improve the catalog performance for large databases with thousands of objects. +- This adapter now implements interactions for catalog items, like dropping tables, inserting columns at the cursor, etc. + +## [1.0.0] - 2025-01-07 + +- Drops support for Python 3.8 +- Adds support for Python 3.13 +- Adds support for Harlequin 2.X + +## [0.3.0] - 2024-08-20 + +- Implements `connection_id` for better persistence. +- Implements the `cancel()` protocol to cancel in-flight queries. +- Implements `close()` +- Fixes a bug where a race condition could cause a crash with an `AssertionError` ([#14](https://github.com/tconbeer/harlequin-mysql/issues/14) - thank you [@blasferna](https://github.com/blasferna)!). + +## [0.2.0] - 2024-04-11 + +### Features + +- Adds a `pool-size` CLI option to set the size of the MySQL connection pool. Defaults to 5. + +### Bug Fixes + +- Updates the connection pool config to keep all connections in sync after running a `use database` command ([#11](https://github.com/tconbeer/harlequin-mysql/issues/11) - thank you [@mlopezgva](https://github.com/mlopezgva)!). +- Handles several issues caused by running too many concurrent queries and not fetching results. + +## [0.1.3] - 2024-01-29 + +### Fixes + +- Fixes a typo in the help text for the `--user` option (thank you [@alexmalins](https://github.com/alexmalins)!). + +## [0.1.2] - 2024-01-25 + +### Fixes + +- Sets the `pool_name` property on the MySQL connection to prevent auto-generated pool names from being too long ([#6](https://github.com/tconbeer/harlequin-mysql/issues/6) - thank you [sondeokhyeon](https://github.com/sondeokhyeon)!). + +## [0.1.1] - 2024-01-09 + +### Fixes + +- Sorts relation names alphabetically and columns by ordinal position. + +## [0.1.0] - 2023-12-14 + +### Features + +- Adds a basic MySQL adapter with most common connection options. + +[Unreleased]: https://github.com/tconbeer/harlequin-mysql/compare/1.1.0...HEAD + +[1.1.0]: https://github.com/tconbeer/harlequin-mysql/compare/1.0.0...1.1.0 + +[1.0.0]: https://github.com/tconbeer/harlequin-mysql/compare/0.3.0...1.0.0 + +[0.3.0]: https://github.com/tconbeer/harlequin-mysql/compare/0.2.0...0.3.0 + +[0.2.0]: https://github.com/tconbeer/harlequin-mysql/compare/0.1.3...0.2.0 + +[0.1.3]: https://github.com/tconbeer/harlequin-mysql/compare/0.1.2...0.1.3 + +[0.1.2]: https://github.com/tconbeer/harlequin-mysql/compare/0.1.1...0.1.2 + +[0.1.1]: https://github.com/tconbeer/harlequin-mysql/compare/0.1.0...0.1.1 + +[0.1.0]: https://github.com/tconbeer/harlequin-mysql/compare/f2caef7de11e68bb2b9798fb597c3fc05044b71e...0.1.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..04ec0c8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Ted Conbeer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6c1e4ac --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +.PHONY: check +check: + ruff format . + ruff check . --fix + mypy + pytest + +.PHONY: init +init: + docker-compose up -d + +.PHONY: clean +clean: + docker-compose down + +.PHONY: serve +serve: + harlequin -P None -a mysql -h localhost -U root --password example --database dev diff --git a/README.md b/README.md new file mode 100644 index 0000000..3f7e08b --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# harlequin-mysql + +This repo provides the Harlequin adapter for MySQL. + +## Installation + +`harlequin-mysql` depends on `harlequin`, so installing this package will also install Harlequin. + +### Using pip + +To install this adapter into an activated virtual environment: +```bash +pip install harlequin-mysql +``` + +### Using poetry + +```bash +poetry add harlequin-mysql +``` + +### Using pipx + +If you do not already have Harlequin installed: + +```bash +pip install harlequin-mysql +``` + +If you would like to add the Postgres adapter to an existing Harlequin installation: + +```bash +pipx inject harlequin harlequin-mysql +``` + +### As an Extra +Alternatively, you can install Harlequin with the `mysql` extra: + +```bash +pip install harlequin[mysql] +``` + +```bash +poetry add harlequin[mysql] +``` + +```bash +pipx install harlequin[mysql] +``` + +## Usage and Configuration + +You can open Harlequin with the MySQL adapter by selecting it with the `-a` option and passing connection parameters as CLI options: + +```bash +harlequin -a mysql -h localhost -p 3306 -U root --password example --database dev +``` + +The MySQL adapter does not accept a connection string or DSN. + +Many more options are available; to see the full list, run: + +```bash +harlequin --help +``` + +For more information, see the [Harlequin Docs](https://harlequin.sh/docs/mysql/index). \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cb0c7c0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + + db: + image: mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: example + ports: + - 3306:3306 diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..1782c39 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1483 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "distlib" +version = "0.3.9" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + +[[package]] +name = "duckdb" +version = "1.1.3" +description = "DuckDB in-process database" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "duckdb-1.1.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:1c0226dc43e2ee4cc3a5a4672fddb2d76fd2cf2694443f395c02dd1bea0b7fce"}, + {file = "duckdb-1.1.3-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:7c71169fa804c0b65e49afe423ddc2dc83e198640e3b041028da8110f7cd16f7"}, + {file = "duckdb-1.1.3-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:872d38b65b66e3219d2400c732585c5b4d11b13d7a36cd97908d7981526e9898"}, + {file = "duckdb-1.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25fb02629418c0d4d94a2bc1776edaa33f6f6ccaa00bd84eb96ecb97ae4b50e9"}, + {file = "duckdb-1.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3f5cd604e7c39527e6060f430769b72234345baaa0987f9500988b2814f5e4"}, + {file = "duckdb-1.1.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08935700e49c187fe0e9b2b86b5aad8a2ccd661069053e38bfaed3b9ff795efd"}, + {file = "duckdb-1.1.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9b47036945e1db32d70e414a10b1593aec641bd4c5e2056873d971cc21e978b"}, + {file = "duckdb-1.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:35c420f58abc79a68a286a20fd6265636175fadeca1ce964fc8ef159f3acc289"}, + {file = "duckdb-1.1.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:4f0e2e5a6f5a53b79aee20856c027046fba1d73ada6178ed8467f53c3877d5e0"}, + {file = "duckdb-1.1.3-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:911d58c22645bfca4a5a049ff53a0afd1537bc18fedb13bc440b2e5af3c46148"}, + {file = "duckdb-1.1.3-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:c443d3d502335e69fc1e35295fcfd1108f72cb984af54c536adfd7875e79cee5"}, + {file = "duckdb-1.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a55169d2d2e2e88077d91d4875104b58de45eff6a17a59c7dc41562c73df4be"}, + {file = "duckdb-1.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d0767ada9f06faa5afcf63eb7ba1befaccfbcfdac5ff86f0168c673dd1f47aa"}, + {file = "duckdb-1.1.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51c6d79e05b4a0933672b1cacd6338f882158f45ef9903aef350c4427d9fc898"}, + {file = "duckdb-1.1.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:183ac743f21c6a4d6adfd02b69013d5fd78e5e2cd2b4db023bc8a95457d4bc5d"}, + {file = "duckdb-1.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:a30dd599b8090ea6eafdfb5a9f1b872d78bac318b6914ada2d35c7974d643640"}, + {file = "duckdb-1.1.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:a433ae9e72c5f397c44abdaa3c781d94f94f4065bcbf99ecd39433058c64cb38"}, + {file = "duckdb-1.1.3-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:d08308e0a46c748d9c30f1d67ee1143e9c5ea3fbcccc27a47e115b19e7e78aa9"}, + {file = "duckdb-1.1.3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:5d57776539211e79b11e94f2f6d63de77885f23f14982e0fac066f2885fcf3ff"}, + {file = "duckdb-1.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e59087dbbb63705f2483544e01cccf07d5b35afa58be8931b224f3221361d537"}, + {file = "duckdb-1.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ebf5f60ddbd65c13e77cddb85fe4af671d31b851f125a4d002a313696af43f1"}, + {file = "duckdb-1.1.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4ef7ba97a65bd39d66f2a7080e6fb60e7c3e41d4c1e19245f90f53b98e3ac32"}, + {file = "duckdb-1.1.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f58db1b65593ff796c8ea6e63e2e144c944dd3d51c8d8e40dffa7f41693d35d3"}, + {file = "duckdb-1.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:e86006958e84c5c02f08f9b96f4bc26990514eab329b1b4f71049b3727ce5989"}, + {file = "duckdb-1.1.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:0897f83c09356206ce462f62157ce064961a5348e31ccb2a557a7531d814e70e"}, + {file = "duckdb-1.1.3-cp313-cp313-macosx_12_0_universal2.whl", hash = "sha256:cddc6c1a3b91dcc5f32493231b3ba98f51e6d3a44fe02839556db2b928087378"}, + {file = "duckdb-1.1.3-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:1d9ab6143e73bcf17d62566e368c23f28aa544feddfd2d8eb50ef21034286f24"}, + {file = "duckdb-1.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f073d15d11a328f2e6d5964a704517e818e930800b7f3fa83adea47f23720d3"}, + {file = "duckdb-1.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5724fd8a49e24d730be34846b814b98ba7c304ca904fbdc98b47fa95c0b0cee"}, + {file = "duckdb-1.1.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51e7dbd968b393343b226ab3f3a7b5a68dee6d3fe59be9d802383bf916775cb8"}, + {file = "duckdb-1.1.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00cca22df96aa3473fe4584f84888e2cf1c516e8c2dd837210daec44eadba586"}, + {file = "duckdb-1.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:77f26884c7b807c7edd07f95cf0b00e6d47f0de4a534ac1706a58f8bc70d0d31"}, + {file = "duckdb-1.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4748635875fc3c19a7320a6ae7410f9295557450c0ebab6d6712de12640929a"}, + {file = "duckdb-1.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74e121ab65dbec5290f33ca92301e3a4e81797966c8d9feef6efdf05fc6dafd"}, + {file = "duckdb-1.1.3-cp37-cp37m-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c619e4849837c8c83666f2cd5c6c031300cd2601e9564b47aa5de458ff6e69d"}, + {file = "duckdb-1.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0ba6baa0af33ded836b388b09433a69b8bec00263247f6bf0a05c65c897108d3"}, + {file = "duckdb-1.1.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:ecb1dc9062c1cc4d2d88a5e5cd8cc72af7818ab5a3c0f796ef0ffd60cfd3efb4"}, + {file = "duckdb-1.1.3-cp38-cp38-macosx_12_0_universal2.whl", hash = "sha256:5ace6e4b1873afdd38bd6cc8fcf90310fb2d454f29c39a61d0c0cf1a24ad6c8d"}, + {file = "duckdb-1.1.3-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:a1fa0c502f257fa9caca60b8b1478ec0f3295f34bb2efdc10776fc731b8a6c5f"}, + {file = "duckdb-1.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6411e21a2128d478efbd023f2bdff12464d146f92bc3e9c49247240448ace5a6"}, + {file = "duckdb-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5336939d83837af52731e02b6a78a446794078590aa71fd400eb17f083dda3e"}, + {file = "duckdb-1.1.3-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f549af9f7416573ee48db1cf8c9d27aeed245cb015f4b4f975289418c6cf7320"}, + {file = "duckdb-1.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:2141c6b28162199999075d6031b5d63efeb97c1e68fb3d797279d31c65676269"}, + {file = "duckdb-1.1.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:09c68522c30fc38fc972b8a75e9201616b96ae6da3444585f14cf0d116008c95"}, + {file = "duckdb-1.1.3-cp39-cp39-macosx_12_0_universal2.whl", hash = "sha256:8ee97ec337794c162c0638dda3b4a30a483d0587deda22d45e1909036ff0b739"}, + {file = "duckdb-1.1.3-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:a1f83c7217c188b7ab42e6a0963f42070d9aed114f6200e3c923c8899c090f16"}, + {file = "duckdb-1.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1aa3abec8e8995a03ff1a904b0e66282d19919f562dd0a1de02f23169eeec461"}, + {file = "duckdb-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80158f4c7c7ada46245837d5b6869a336bbaa28436fbb0537663fa324a2750cd"}, + {file = "duckdb-1.1.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:647f17bd126170d96a38a9a6f25fca47ebb0261e5e44881e3782989033c94686"}, + {file = "duckdb-1.1.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:252d9b17d354beb9057098d4e5d5698e091a4f4a0d38157daeea5fc0ec161670"}, + {file = "duckdb-1.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:eeacb598120040e9591f5a4edecad7080853aa8ac27e62d280f151f8c862afa3"}, + {file = "duckdb-1.1.3.tar.gz", hash = "sha256:68c3a46ab08836fe041d15dcbf838f74a990d551db47cb24ab1c4576fc19351c"}, +] + +[[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 = "filelock" +version = "3.17.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.9" +files = [ + {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, + {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] +typing = ["typing-extensions (>=4.12.2)"] + +[[package]] +name = "harlequin" +version = "2.0.0" +description = "The SQL IDE for Your Terminal." +optional = false +python-versions = "<3.14.0,>=3.9" +files = [ + {file = "harlequin-2.0.0-py3-none-any.whl", hash = "sha256:40ef0b0436eba08501fd45e533c49add40b0855320bb42a1b84e98c53dc5a312"}, + {file = "harlequin-2.0.0.tar.gz", hash = "sha256:d9bb419859bf35263e0a6875592b72b81f4aab70373a55c937cfc608c38585cd"}, +] + +[package.dependencies] +click = ">=8.1.3,<9.0.0" +duckdb = ">=0.8.0" +importlib_metadata = {version = ">=8.0", markers = "python_full_version < \"3.10.0\""} +numpy = [ + {version = ">=1.21.0,<2.0.0", markers = "python_full_version < \"3.12.0\""}, + {version = ">=1.26.0,<2.0.0", markers = "python_full_version >= \"3.12.0\""}, +] +platformdirs = ">=3.10,<5.0" +pyarrow = {version = ">=18.1.0", markers = "python_full_version >= \"3.12.0\""} +questionary = ">=2.0.1,<3.0.0" +rich-click = ">=1.7.1,<2.0.0" +shandy-sqlfmt = ">=0.19.0" +textual = "0.89.1" +textual-fastdatatable = "0.11.0" +textual-textarea = "0.15.0" +tomlkit = ">=0.12.5,<0.14.0" + +[package.extras] +adbc = ["harlequin-adbc (>=0.1)"] +bigquery = ["harlequin-bigquery (>=1.0.3)"] +databricks = ["harlequin-databricks (>=0.5.2)"] +mysql = ["harlequin-mysql (>=1.0)"] +odbc = ["harlequin-odbc (>=0.2)"] +postgres = ["harlequin-postgres (>=1.0)"] +s3 = ["boto3 (>=1.34.22,<2.0.0)"] +trino = ["harlequin-trino (>=0.1)"] + +[[package]] +name = "identify" +version = "2.6.6" +description = "File identification library for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881"}, + {file = "identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "importlib-metadata" +version = "8.6.1" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +files = [ + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jinja2" +version = "3.1.5" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "linkify-it-py" +version = "2.0.3" +description = "Links recognition library with FULL unicode support." +optional = false +python-versions = ">=3.7" +files = [ + {file = "linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048"}, + {file = "linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"}, +] + +[package.dependencies] +uc-micro-py = "*" + +[package.extras] +benchmark = ["pytest", "pytest-benchmark"] +dev = ["black", "flake8", "isort", "pre-commit", "pyproject-flake8"] +doc = ["myst-parser", "sphinx", "sphinx-book-theme"] +test = ["coverage", "pytest", "pytest-cov"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +linkify-it-py = {version = ">=1,<3", optional = true, markers = "extra == \"linkify\""} +mdit-py-plugins = {version = "*", optional = true, markers = "extra == \"plugins\""} +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "3.0.2" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.2" +description = "Collection of plugins for markdown-it-py" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mypy" +version = "1.14.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"}, + {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"}, + {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"}, + {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"}, + {file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"}, + {file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"}, + {file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"}, + {file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"}, + {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"}, + {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"}, + {file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"}, + {file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"}, + {file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"}, + {file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"}, + {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"}, + {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"}, + {file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"}, + {file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"}, + {file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"}, + {file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"}, + {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"}, + {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"}, + {file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"}, + {file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"}, + {file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"}, + {file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"}, + {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"}, + {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"}, + {file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"}, + {file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"}, + {file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"}, + {file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"}, + {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"}, + {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"}, + {file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"}, + {file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"}, + {file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"}, + {file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"}, +] + +[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"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "mysql-connector-python" +version = "9.2.0" +description = "A self-contained Python driver for communicating with MySQL servers, using an API that is compliant with the Python Database API Specification v2.0 (PEP 249)." +optional = false +python-versions = ">=3.9" +files = [ + {file = "mysql_connector_python-9.2.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:65808b0a9998150416ee0b5781fdff456faea247e24d505f606aea2acaf21374"}, + {file = "mysql_connector_python-9.2.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:877552ff04800be4a53604bfee95b4078d10fcc072d54b9ea8dcd159c692742c"}, + {file = "mysql_connector_python-9.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8a6cfb611bdfea41c67c5305e8fc0e30fdacd258c489dc619f566213cce8bba9"}, + {file = "mysql_connector_python-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c25dc2cb4fca82242d71a0bda2087bdfa3638e0c8175a747a6e765242763b4a"}, + {file = "mysql_connector_python-9.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5c72ecad9007bc52d4f213e47d3c4cf17b3a3cabfeb2d36317fd4493adf5ed7d"}, + {file = "mysql_connector_python-9.2.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bddecd023c0e92182eb3159abee7385a1d38b395a58ff4d94d3d6f1abeca6334"}, + {file = "mysql_connector_python-9.2.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cc09ca64db620f7c898e1fb7c61a3d6f8f21694fcd276ab2635650ce216f8556"}, + {file = "mysql_connector_python-9.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4142a0a4e997210558136ad2b623188c102996eda2d951a3933d6338b210f15e"}, + {file = "mysql_connector_python-9.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e1afa12519671e024d80fbbf74606cc4fb96786b005d79ed959acf3584ba6af4"}, + {file = "mysql_connector_python-9.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:cf2684641084abc47be2dbba7bd42ce22c682bad4228a10bb12c343e1ecfc484"}, + {file = "mysql_connector_python-9.2.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:03fe54ca19c2dffa8f04ca0601a1217b126ff8306c76a9b2b4e555f8fbbd2178"}, + {file = "mysql_connector_python-9.2.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b13b136c188363e18f9b3f6237a0e6eba8601df259ab0f8687cd689f433a391b"}, + {file = "mysql_connector_python-9.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e8338a9babe6c67287080ec9f6a0fc245de24841bc532ef97dfd1f93caf4668b"}, + {file = "mysql_connector_python-9.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:92ef9e5a37b25978a261b5a14fcfa0cf51cd96168dec4a52657bbfc1e1cb7d9a"}, + {file = "mysql_connector_python-9.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b7d149bcc455cf606a4aa604d45267fba16c8abf36056b804f8d16e8f5e753c1"}, + {file = "mysql_connector_python-9.2.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:417c538dfd64e6d415280067f4d7ce3f901ce85c548e609247a794d205769276"}, + {file = "mysql_connector_python-9.2.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4d97485eb3f63ab26f6438570c4a392bb1f53c3ad9dca1bfd8b61b5ec1bba690"}, + {file = "mysql_connector_python-9.2.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c2e973bcc6eab68e41e01438b706788e3f47b0b4d6a17fcb74583f7e0b990c5f"}, + {file = "mysql_connector_python-9.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:2238ba121a30dd3a23d33ce3437642e38a1d4b86afaf7a487cdb0d7727db2010"}, + {file = "mysql_connector_python-9.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:6557942f6c6be3b41d2965456b53a244a7ce3e6fb81cb195c243549be72a6a24"}, + {file = "mysql_connector_python-9.2.0-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:0aee4e3a053672ded2134eda6fff3bc64796df88c9a9e5cab130b576830e14a8"}, + {file = "mysql_connector_python-9.2.0-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:86c3217849857113912e8fc628e13182f00955ed1257cb7bfdc3d5ac3c5ff371"}, + {file = "mysql_connector_python-9.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2a96bed643e901e91c05f421a37844939f5e2f65cc54a406ec5d95e704bda068"}, + {file = "mysql_connector_python-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:292974916c6908e62bb0eb864c1c5679aa5c827209a200b5658aa4b4468c19a0"}, + {file = "mysql_connector_python-9.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:2c358b5732666043683445e88405d58232d5bb0977d24ec55e02a315b33fecbc"}, + {file = "mysql_connector_python-9.2.0-py2.py3-none-any.whl", hash = "sha256:d007c05a48fc076e5ac7ad3d76e332fa5b0e885853c2da80071ade2d6e01aba5"}, +] + +[package.extras] +dns-srv = ["dnspython (==2.6.1)"] +fido2 = ["fido2 (==1.1.2)"] +gssapi = ["gssapi (==1.8.3)"] +telemetry = ["opentelemetry-api (==1.18.0)", "opentelemetry-exporter-otlp-proto-http (==1.18.0)", "opentelemetry-sdk (==1.18.0)"] + +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.8.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "prompt-toolkit" +version = "3.0.50" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, + {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "pyarrow" +version = "19.0.0" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pyarrow-19.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c318eda14f6627966997a7d8c374a87d084a94e4e38e9abbe97395c215830e0c"}, + {file = "pyarrow-19.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:62ef8360ff256e960f57ce0299090fb86423afed5e46f18f1225f960e05aae3d"}, + {file = "pyarrow-19.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2795064647add0f16563e57e3d294dbfc067b723f0fd82ecd80af56dad15f503"}, + {file = "pyarrow-19.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a218670b26fb1bc74796458d97bcab072765f9b524f95b2fccad70158feb8b17"}, + {file = "pyarrow-19.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:66732e39eaa2247996a6b04c8aa33e3503d351831424cdf8d2e9a0582ac54b34"}, + {file = "pyarrow-19.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e675a3ad4732b92d72e4d24009707e923cab76b0d088e5054914f11a797ebe44"}, + {file = "pyarrow-19.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:f094742275586cdd6b1a03655ccff3b24b2610c3af76f810356c4c71d24a2a6c"}, + {file = "pyarrow-19.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8e3a839bf36ec03b4315dc924d36dcde5444a50066f1c10f8290293c0427b46a"}, + {file = "pyarrow-19.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:ce42275097512d9e4e4a39aade58ef2b3798a93aa3026566b7892177c266f735"}, + {file = "pyarrow-19.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9348a0137568c45601b031a8d118275069435f151cbb77e6a08a27e8125f59d4"}, + {file = "pyarrow-19.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0144a712d990d60f7f42b7a31f0acaccf4c1e43e957f7b1ad58150d6f639c1"}, + {file = "pyarrow-19.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2a1a109dfda558eb011e5f6385837daffd920d54ca00669f7a11132d0b1e6042"}, + {file = "pyarrow-19.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:be686bf625aa7b9bada18defb3a3ea3981c1099697239788ff111d87f04cd263"}, + {file = "pyarrow-19.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:239ca66d9a05844bdf5af128861af525e14df3c9591bcc05bac25918e650d3a2"}, + {file = "pyarrow-19.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:a7bbe7109ab6198688b7079cbad5a8c22de4d47c4880d8e4847520a83b0d1b68"}, + {file = "pyarrow-19.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:4624c89d6f777c580e8732c27bb8e77fd1433b89707f17c04af7635dd9638351"}, + {file = "pyarrow-19.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b6d3ce4288793350dc2d08d1e184fd70631ea22a4ff9ea5c4ff182130249d9b"}, + {file = "pyarrow-19.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:450a7d27e840e4d9a384b5c77199d489b401529e75a3b7a3799d4cd7957f2f9c"}, + {file = "pyarrow-19.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a08e2a8a039a3f72afb67a6668180f09fddaa38fe0d21f13212b4aba4b5d2451"}, + {file = "pyarrow-19.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f43f5aef2a13d4d56adadae5720d1fed4c1356c993eda8b59dace4b5983843c1"}, + {file = "pyarrow-19.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f672f5364b2d7829ef7c94be199bb88bf5661dd485e21d2d37de12ccb78a136"}, + {file = "pyarrow-19.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:cf3bf0ce511b833f7bc5f5bb3127ba731e97222023a444b7359f3a22e2a3b463"}, + {file = "pyarrow-19.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:4d8b0c0de0a73df1f1bf439af1b60f273d719d70648e898bc077547649bb8352"}, + {file = "pyarrow-19.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92aff08e23d281c69835e4a47b80569242a504095ef6a6223c1f6bb8883431d"}, + {file = "pyarrow-19.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3b78eff5968a1889a0f3bc81ca57e1e19b75f664d9c61a42a604bf9d8402aae"}, + {file = "pyarrow-19.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:b34d3bde38eba66190b215bae441646330f8e9da05c29e4b5dd3e41bde701098"}, + {file = "pyarrow-19.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5418d4d0fab3a0ed497bad21d17a7973aad336d66ad4932a3f5f7480d4ca0c04"}, + {file = "pyarrow-19.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:e82c3d5e44e969c217827b780ed8faf7ac4c53f934ae9238872e749fa531f7c9"}, + {file = "pyarrow-19.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:f208c3b58a6df3b239e0bb130e13bc7487ed14f39a9ff357b6415e3f6339b560"}, + {file = "pyarrow-19.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:c751c1c93955b7a84c06794df46f1cec93e18610dcd5ab7d08e89a81df70a849"}, + {file = "pyarrow-19.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b903afaa5df66d50fc38672ad095806443b05f202c792694f3a604ead7c6ea6e"}, + {file = "pyarrow-19.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22a4bc0937856263df8b94f2f2781b33dd7f876f787ed746608e06902d691a5"}, + {file = "pyarrow-19.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:5e8a28b918e2e878c918f6d89137386c06fe577cd08d73a6be8dafb317dc2d73"}, + {file = "pyarrow-19.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:29cd86c8001a94f768f79440bf83fee23963af5e7bc68ce3a7e5f120e17edf89"}, + {file = "pyarrow-19.0.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:c0423393e4a07ff6fea08feb44153302dd261d0551cc3b538ea7a5dc853af43a"}, + {file = "pyarrow-19.0.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:718947fb6d82409013a74b176bf93e0f49ef952d8a2ecd068fecd192a97885b7"}, + {file = "pyarrow-19.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c1c162c4660e0978411a4761f91113dde8da3433683efa473501254563dcbe8"}, + {file = "pyarrow-19.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c73268cf557e688efb60f1ccbc7376f7e18cd8e2acae9e663e98b194c40c1a2d"}, + {file = "pyarrow-19.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:edfe6d3916e915ada9acc4e48f6dafca7efdbad2e6283db6fd9385a1b23055f1"}, + {file = "pyarrow-19.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:da410b70a7ab8eb524112f037a7a35da7128b33d484f7671a264a4c224ac131d"}, + {file = "pyarrow-19.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:597360ffc71fc8cceea1aec1fb60cb510571a744fffc87db33d551d5de919bec"}, + {file = "pyarrow-19.0.0.tar.gz", hash = "sha256:8d47c691765cf497aaeed4954d226568563f1b3b74ff61139f2d77876717084b"}, +] + +[package.extras] +test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] + +[[package]] +name = "pygments" +version = "2.19.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyperclip" +version = "1.9.0" +description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)" +optional = false +python-versions = "*" +files = [ + {file = "pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310"}, +] + +[[package]] +name = "pytest" +version = "8.3.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {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"] + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "questionary" +version = "2.1.0" +description = "Python library to build pretty command line user prompts ⭐️" +optional = false +python-versions = ">=3.8" +files = [ + {file = "questionary-2.1.0-py3-none-any.whl", hash = "sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec"}, + {file = "questionary-2.1.0.tar.gz", hash = "sha256:6302cdd645b19667d8f6e6634774e9538bfcd1aad9be287e743d96cacaf95587"}, +] + +[package.dependencies] +prompt_toolkit = ">=2.0,<4.0" + +[[package]] +name = "rich" +version = "13.9.4" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rich-click" +version = "1.8.5" +description = "Format click help output nicely with rich" +optional = false +python-versions = ">=3.7" +files = [ + {file = "rich_click-1.8.5-py3-none-any.whl", hash = "sha256:0fab7bb5b66c15da17c210b4104277cd45f3653a7322e0098820a169880baee0"}, + {file = "rich_click-1.8.5.tar.gz", hash = "sha256:a3eebe81da1c9da3c32f3810017c79bd687ff1b3fa35bfc9d8a3338797f1d1a1"}, +] + +[package.dependencies] +click = ">=7" +rich = ">=10.7" +typing_extensions = ">=4" + +[package.extras] +dev = ["mypy", "packaging", "pre-commit", "pytest", "pytest-cov", "rich-codex", "ruff", "types-setuptools"] +docs = ["markdown_include", "mkdocs", "mkdocs-glightbox", "mkdocs-material-extensions", "mkdocs-material[imaging] (>=9.5.18,<9.6.0)", "mkdocs-rss-plugin", "mkdocstrings[python]", "rich-codex"] + +[[package]] +name = "ruff" +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.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]] +name = "shandy-sqlfmt" +version = "0.26.0" +description = "sqlfmt formats your dbt SQL files so you don't have to." +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "shandy_sqlfmt-0.26.0-py3-none-any.whl", hash = "sha256:bb7c310af67c50973dc428a07d491b3478141cfe0a068f742b0cfd01ed9c251e"}, + {file = "shandy_sqlfmt-0.26.0.tar.gz", hash = "sha256:d95abd381640a846c71b0e2effb30d47f0b3eb5f69fb337fafe663634857f7a5"}, +] + +[package.dependencies] +click = ">=8.0,<9.0" +jinja2 = ">=3.0,<4.0" +platformdirs = ">=2.4,<5.0" +tomli = {version = ">=2.0,<3.0", markers = "python_version < \"3.11\""} +tqdm = ">=4.0,<5.0" + +[package.extras] +jinjafmt = ["black"] +sqlfmt-primer = ["gitpython (>=3.1.24,<4.0.0)"] + +[[package]] +name = "textual" +version = "0.89.1" +description = "Modern Text User Interface framework" +optional = false +python-versions = "<4.0.0,>=3.8.1" +files = [ + {file = "textual-0.89.1-py3-none-any.whl", hash = "sha256:0a5d214df6e951b4a2c421e13d0b608482882471c1e34ea74a3631adede8054f"}, + {file = "textual-0.89.1.tar.gz", hash = "sha256:66befe80e2bca5a8c876cd8ceeaf01752267b6b1dc1d0f73071f1f1e15d90cc8"}, +] + +[package.dependencies] +markdown-it-py = {version = ">=2.1.0", extras = ["linkify", "plugins"]} +platformdirs = ">=3.6.0,<5" +rich = ">=13.3.3" +tree-sitter = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-bash = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-css = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-go = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-html = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-java = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-javascript = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-json = {version = ">=0.24.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-markdown = {version = ">=0.3.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-python = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-regex = {version = ">=0.24.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-rust = {version = ">=0.23.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-sql = {version = ">=0.3.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-toml = {version = ">=0.6.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-xml = {version = ">=0.7.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +tree-sitter-yaml = {version = ">=0.6.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"syntax\""} +typing-extensions = ">=4.4.0,<5.0.0" + +[package.extras] +syntax = ["tree-sitter (>=0.23.0)", "tree-sitter-bash (>=0.23.0)", "tree-sitter-css (>=0.23.0)", "tree-sitter-go (>=0.23.0)", "tree-sitter-html (>=0.23.0)", "tree-sitter-java (>=0.23.0)", "tree-sitter-javascript (>=0.23.0)", "tree-sitter-json (>=0.24.0)", "tree-sitter-markdown (>=0.3.0)", "tree-sitter-python (>=0.23.0)", "tree-sitter-regex (>=0.24.0)", "tree-sitter-rust (>=0.23.0)", "tree-sitter-sql (>=0.3.0)", "tree-sitter-toml (>=0.6.0)", "tree-sitter-xml (>=0.7.0)", "tree-sitter-yaml (>=0.6.0)"] + +[[package]] +name = "textual-fastdatatable" +version = "0.11.0" +description = "A performance-focused reimplementation of Textual's DataTable widget, with a pluggable data storage backend." +optional = false +python-versions = "<3.14,>=3.9" +files = [ + {file = "textual_fastdatatable-0.11.0-py3-none-any.whl", hash = "sha256:23be3ee1748075a06aed7352067327de09179f791e16a1d1d6a01b1fcc1e3613"}, + {file = "textual_fastdatatable-0.11.0.tar.gz", hash = "sha256:a2305f5745dc1ab4088a3f0d5c7dcfb8993d711a296954664c3492712fa5cc4b"}, +] + +[package.dependencies] +pyarrow = ">=16.1.0" +textual = ">=0.89.1" +tzdata = {version = ">=2023", markers = "sys_platform == \"win32\""} + +[package.extras] +polars = ["polars (>=0.20.0)"] + +[[package]] +name = "textual-textarea" +version = "0.15.0" +description = "A text area (multi-line input) with syntax highlighting for Textual" +optional = false +python-versions = "<3.14,>=3.9" +files = [ + {file = "textual_textarea-0.15.0-py3-none-any.whl", hash = "sha256:bdaee55bb3cb2544ad5723fe9c3fcf6e31bc572772f6e95ea769d384a00e76d9"}, + {file = "textual_textarea-0.15.0.tar.gz", hash = "sha256:1343604a4dc3bac0337c58d926a02ddcf451956fb12532a3d5ade9219905f426"}, +] + +[package.dependencies] +pyperclip = ">=1.9.0,<2.0.0" +textual = {version = ">=0.89.1,<2.0", extras = ["syntax"]} + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.2" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "tree-sitter" +version = "0.23.2" +description = "Python bindings to the Tree-sitter parsing library" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree-sitter-0.23.2.tar.gz", hash = "sha256:66bae8dd47f1fed7bdef816115146d3a41c39b5c482d7bad36d9ba1def088450"}, + {file = "tree_sitter-0.23.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3a937f5d8727bc1c74c4bf2a9d1c25ace049e8628273016ad0d45914ae904e10"}, + {file = "tree_sitter-0.23.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2c7eae7fe2af215645a38660d2d57d257a4c461fe3ec827cca99a79478284e80"}, + {file = "tree_sitter-0.23.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a71d607595270b6870eaf778a1032d146b2aa79bfcfa60f57a82a7b7584a4c7"}, + {file = "tree_sitter-0.23.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe9b9ea7a0aa23b52fd97354da95d1b2580065bc12a4ac868f9164a127211d6"}, + {file = "tree_sitter-0.23.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d74d00a8021719eae14d10d1b1e28649e15d8b958c01c2b2c3dad7a2ebc4dbae"}, + {file = "tree_sitter-0.23.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6de18d8d8a7f67ab71f472d1fcb01cc506e080cbb5e13d52929e4b6fdce6bbee"}, + {file = "tree_sitter-0.23.2-cp310-cp310-win_amd64.whl", hash = "sha256:12b60dca70d2282af942b650a6d781be487485454668c7c956338a367b98cdee"}, + {file = "tree_sitter-0.23.2-cp310-cp310-win_arm64.whl", hash = "sha256:3346a4dd0447a42aabb863443b0fd8c92b909baf40ed2344fae4b94b625d5955"}, + {file = "tree_sitter-0.23.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91fda41d4f8824335cc43c64e2c37d8089c8c563bd3900a512d2852d075af719"}, + {file = "tree_sitter-0.23.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:92b2b489d5ce54b41f94c6f23fbaf592bd6e84dc2877048fd1cb060480fa53f7"}, + {file = "tree_sitter-0.23.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64859bd4aa1567d0d6016a811b2b49c59d4a4427d096e3d8c84b2521455f62b7"}, + {file = "tree_sitter-0.23.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:614590611636044e071d3a0b748046d52676dbda3bc9fa431216231e11dd98f7"}, + {file = "tree_sitter-0.23.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:08466953c78ae57be61057188fb88c89791b0a562856010228e0ccf60e2ac453"}, + {file = "tree_sitter-0.23.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8a33f03a562de91f7fd05eefcedd8994a06cd44c62f7aabace811ad82bc11cbd"}, + {file = "tree_sitter-0.23.2-cp311-cp311-win_amd64.whl", hash = "sha256:03b70296b569ef64f7b92b42ca5da9bf86d81bee2afd480bea35092687f51dae"}, + {file = "tree_sitter-0.23.2-cp311-cp311-win_arm64.whl", hash = "sha256:7cb4bb953ea7c0b50eeafc4454783e030357179d2a93c3dd5ebed2da5588ddd0"}, + {file = "tree_sitter-0.23.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a014498b6a9e6003fae8c6eb72f5927d62da9dcb72b28b3ce8cd15c6ff6a6572"}, + {file = "tree_sitter-0.23.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:04f8699b131d4bcbe3805c37e4ef3d159ee9a82a0e700587625623999ba0ea53"}, + {file = "tree_sitter-0.23.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4471577df285059c71686ecb208bc50fb472099b38dcc8e849b0e86652891e87"}, + {file = "tree_sitter-0.23.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f342c925290dd4e20ecd5787ef7ae8749981597ab364783a1eb73173efe65226"}, + {file = "tree_sitter-0.23.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4e9e53d07dd076bede72e4f7d3a0173d7b9ad6576572dd86da008a740a9bb22"}, + {file = "tree_sitter-0.23.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8caebe65bc358759dac2500d8f8feed3aed939c4ade9a684a1783fe07bc7d5db"}, + {file = "tree_sitter-0.23.2-cp312-cp312-win_amd64.whl", hash = "sha256:fc5a72eb50d43485000dbbb309acb350467b7467e66dc747c6bb82ce63041582"}, + {file = "tree_sitter-0.23.2-cp312-cp312-win_arm64.whl", hash = "sha256:a0320eb6c7993359c5f7b371d22719ccd273f440d41cf1bd65dac5e9587f2046"}, + {file = "tree_sitter-0.23.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eff630dddee7ba05accb439b17e559e15ce13f057297007c246237ceb6306332"}, + {file = "tree_sitter-0.23.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4780ba8f3894f2dea869fad2995c2aceab3fd5ab9e6a27c45475d2acd7f7e84e"}, + {file = "tree_sitter-0.23.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b609460b8e3e256361fb12e94fae5b728cb835b16f0f9d590b5aadbf9d109b"}, + {file = "tree_sitter-0.23.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d070d8eaeaeb36cf535f55e5578fddbfc3bf53c1980f58bf1a99d57466b3b5"}, + {file = "tree_sitter-0.23.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878580b2ad5054c410ba3418edca4d34c81cc26706114d8f5b5541688bc2d785"}, + {file = "tree_sitter-0.23.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:29224bdc2a3b9af535b7725e249d3ee291b2e90708e82832e73acc175e40dc48"}, + {file = "tree_sitter-0.23.2-cp313-cp313-win_amd64.whl", hash = "sha256:c58d89348162fbc3aea1fe6511a66ee189fc0e4e4bbe937026f29e4ecef17763"}, + {file = "tree_sitter-0.23.2-cp313-cp313-win_arm64.whl", hash = "sha256:0ff2037be5edab7801de3f6a721b9cf010853f612e2008ee454e0e0badb225a6"}, + {file = "tree_sitter-0.23.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a5db8e585205faef8bf219da77d8993e2ef04d08eda2e3c8ad7e4df8297ee344"}, + {file = "tree_sitter-0.23.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9dbd110a30cf28be5da734ae4cd0e9031768228dbf6a79f2973962aa51de4ec7"}, + {file = "tree_sitter-0.23.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569514b9a996a0fd458b3a891c46ca125298be0c03cf82f2b6f0c13d5d8f25dc"}, + {file = "tree_sitter-0.23.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a357ed98a74e47787b812df99a74a2c35c0fe11e55c2095cc01d1cad144ef552"}, + {file = "tree_sitter-0.23.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c2dfb8e8f760f4cc67888d03ef9e2dbd3353245f67f5efba375c2a14d944ac0e"}, + {file = "tree_sitter-0.23.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3ead958df87a21d706903987e665e9e0e5df7b2c5021ff69ea349826840adc6a"}, + {file = "tree_sitter-0.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:611cae16be332213c0e6ece72c0bfca202e30ff320a8b309b1526c6cb79ee4ba"}, + {file = "tree_sitter-0.23.2-cp39-cp39-win_arm64.whl", hash = "sha256:b848e0fdd522fbb8888cdb4f4d93f8fad97ae10d70c122fb922e51363c7febcd"}, +] + +[package.extras] +docs = ["sphinx (>=7.3,<8.0)", "sphinx-book-theme"] +tests = ["tree-sitter-html (>=0.23.0)", "tree-sitter-javascript (>=0.23.0)", "tree-sitter-json (>=0.23.0)", "tree-sitter-python (>=0.23.0)", "tree-sitter-rust (>=0.23.0)"] + +[[package]] +name = "tree-sitter-bash" +version = "0.23.3" +description = "Bash grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_bash-0.23.3-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c1ee7a46fcbfca9937d01056be756631762f53c5afdb8c4ab64eb9fed060896b"}, + {file = "tree_sitter_bash-0.23.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5a090118e887bf667d82ae445794906186216f5500e0d2cd58eb499f7502dc57"}, + {file = "tree_sitter_bash-0.23.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4b5dde719291eea3a81b1f9ece6afeee2deadc2b2f769bee92f955da7595cf"}, + {file = "tree_sitter_bash-0.23.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff7bffc3d594e7f1054de051e19df1b24082963598a175dda64083c6b3eea1a"}, + {file = "tree_sitter_bash-0.23.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4427baccbd7549a2ebb1859b6d42cdab0739c05d53c2b3daad9cadc069a7b3f6"}, + {file = "tree_sitter_bash-0.23.3-cp39-abi3-win_amd64.whl", hash = "sha256:525c5cce28a7c5624fb016ac8f3ae33d32968567b718f7878c6351229d2e8394"}, + {file = "tree_sitter_bash-0.23.3-cp39-abi3-win_arm64.whl", hash = "sha256:1f703d1bf6235355f6c900be64bf9f61fc4b1d0cfed6829b4eeb74a6b41ea910"}, + {file = "tree_sitter_bash-0.23.3.tar.gz", hash = "sha256:7b15ed89a1ea8e3e3c2399758746413e464d4c1c3a6d3b75d643ae2bc2fb356b"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-css" +version = "0.23.2" +description = "CSS grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_css-0.23.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:62b9eadb8f47c666a36a2ead96d17c2a01d7599e1f13f69c617f08e4acf62bf0"}, + {file = "tree_sitter_css-0.23.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:0be54e07f90679173bb06a8ecf483a7d79eaa6d236419b5baa6ce02401ea31a9"}, + {file = "tree_sitter_css-0.23.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4ac53c7d74fbb88196301f998a3ab06325447175374500aa477211a59372da2"}, + {file = "tree_sitter_css-0.23.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f51bf93f607581ec08c30c591a9274fb29b4b59a1bde4adee7d395de7687285"}, + {file = "tree_sitter_css-0.23.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6d13c0683d259d82bed17d00d788a8af026ffb3f412337e9971324742dcf2cc8"}, + {file = "tree_sitter_css-0.23.2-cp39-abi3-win_amd64.whl", hash = "sha256:78236683eb974cc738969f70f1fb6d978ae375139b89cfe8efeaca4b865055be"}, + {file = "tree_sitter_css-0.23.2-cp39-abi3-win_arm64.whl", hash = "sha256:4b95b7f53142029fca2abd3fcb635e3eb952bc198f340be5c429040c791f9c00"}, + {file = "tree_sitter_css-0.23.2.tar.gz", hash = "sha256:04198e9f4dee4935dbf17fdd7f534be8b9a2dd3a4b44a3ca481d3e8c15f10dca"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-go" +version = "0.23.4" +description = "Go grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_go-0.23.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9320f87a05cd47fa0f627b9329bbc09b7ed90de8fe4f5882aed318d6e19962d"}, + {file = "tree_sitter_go-0.23.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:914e63d16b36ab0e4f52b031e574b82d17d0bbfecca138ae83e887a1cf5b71ac"}, + {file = "tree_sitter_go-0.23.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:330ecbb38d6ea4ef41eba2d473056889705e64f6a51c2fb613de05b1bcb5ba22"}, + {file = "tree_sitter_go-0.23.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd14d23056ae980debfccc0db67d0a168da03792ca2968b1b5dd58ce288084e7"}, + {file = "tree_sitter_go-0.23.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c3b40912487fdb78c4028860dd79493a521ffca0104f209849823358db3618a0"}, + {file = "tree_sitter_go-0.23.4-cp39-abi3-win_amd64.whl", hash = "sha256:ae4b231cad2ef76401d33617879cda6321c4d0853f7fd98cb5654c50a218effb"}, + {file = "tree_sitter_go-0.23.4-cp39-abi3-win_arm64.whl", hash = "sha256:2ac907362a3c347145dc1da0858248546500a323de90d2cb76d2a3fdbfc8da25"}, + {file = "tree_sitter_go-0.23.4.tar.gz", hash = "sha256:0ebff99820657066bec21690623a14c74d9e57a903f95f0837be112ddadf1a52"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-html" +version = "0.23.2" +description = "HTML grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_html-0.23.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e1641d5edf5568a246c6c47b947ed524b5bf944664e6473b21d4ae568e28ee9"}, + {file = "tree_sitter_html-0.23.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:3d0a83dd6cd1c7d4bcf6287b5145c92140f0194f8516f329ae8b9e952fbfa8ff"}, + {file = "tree_sitter_html-0.23.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b3775732fffc0abd275a419ef018fd4c1ad4044b2a2e422f3378d93c30eded"}, + {file = "tree_sitter_html-0.23.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bdaa7ac5030d416aea0c512d4810ef847bbbd62d61e3d213f370b64ce147293"}, + {file = "tree_sitter_html-0.23.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d2e9631b66041a4fd792d7f79a0c4128adb3bfc71f3dcb7e1a3eab5dbee77d67"}, + {file = "tree_sitter_html-0.23.2-cp39-abi3-win_amd64.whl", hash = "sha256:85095f49f9e57f0ac9087a3e830783352c8447fdda55b1c1139aa47e5eaa0e21"}, + {file = "tree_sitter_html-0.23.2-cp39-abi3-win_arm64.whl", hash = "sha256:0f65ed9e877144d0f04ade5644e5b0e88bf98a9e60bce65235c99905623e2f1a"}, + {file = "tree_sitter_html-0.23.2.tar.gz", hash = "sha256:bc9922defe23144d9146bc1509fcd00d361bf6b3303f9effee6532c6a0296961"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-java" +version = "0.23.5" +description = "Java grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_java-0.23.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:355ce0308672d6f7013ec913dee4a0613666f4cda9044a7824240d17f38209df"}, + {file = "tree_sitter_java-0.23.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:24acd59c4720dedad80d548fe4237e43ef2b7a4e94c8549b0ca6e4c4d7bf6e69"}, + {file = "tree_sitter_java-0.23.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9401e7271f0b333df39fc8a8336a0caf1b891d9a2b89ddee99fae66b794fc5b7"}, + {file = "tree_sitter_java-0.23.5-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:370b204b9500b847f6d0c5ad584045831cee69e9a3e4d878535d39e4a7e4c4f1"}, + {file = "tree_sitter_java-0.23.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:aae84449e330363b55b14a2af0585e4e0dae75eb64ea509b7e5b0e1de536846a"}, + {file = "tree_sitter_java-0.23.5-cp39-abi3-win_amd64.whl", hash = "sha256:1ee45e790f8d31d416bc84a09dac2e2c6bc343e89b8a2e1d550513498eedfde7"}, + {file = "tree_sitter_java-0.23.5-cp39-abi3-win_arm64.whl", hash = "sha256:402efe136104c5603b429dc26c7e75ae14faaca54cfd319ecc41c8f2534750f4"}, + {file = "tree_sitter_java-0.23.5.tar.gz", hash = "sha256:f5cd57b8f1270a7f0438878750d02ccc79421d45cca65ff284f1527e9ef02e38"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-javascript" +version = "0.23.1" +description = "JavaScript grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6ca583dad4bd79d3053c310b9f7208cd597fd85f9947e4ab2294658bb5c11e35"}, + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:94100e491a6a247aa4d14caf61230c171b6376c863039b6d9cd71255c2d815ec"}, + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a6bc1055b061c5055ec58f39ee9b2e9efb8e6e0ae970838af74da0afb811f0a"}, + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:056dc04fb6b24293f8c5fec43c14e7e16ba2075b3009c643abf8c85edc4c7c3c"}, + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a11ca1c0f736da42967586b568dff8a465ee148a986c15ebdc9382806e0ce871"}, + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-win_amd64.whl", hash = "sha256:041fa22b34250ea6eb313d33104d5303f79504cb259d374d691e38bbdc49145b"}, + {file = "tree_sitter_javascript-0.23.1-cp39-abi3-win_arm64.whl", hash = "sha256:eb28130cd2fb30d702d614cbf61ef44d1c7f6869e7d864a9cc17111e370be8f7"}, + {file = "tree_sitter_javascript-0.23.1.tar.gz", hash = "sha256:b2059ce8b150162cda05a457ca3920450adbf915119c04b8c67b5241cd7fcfed"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-json" +version = "0.24.8" +description = "JSON grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_json-0.24.8-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:59ac06c6db1877d0e2076bce54a5fddcdd2fc38ca778905662e80fa9ffcea2ab"}, + {file = "tree_sitter_json-0.24.8-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:62b4c45b561db31436a81a3f037f71ec29049f4fc9bf5269b6ec3ebaaa35a1cd"}, + {file = "tree_sitter_json-0.24.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8627f7d375fda9fc193ebee368c453f374f65c2f25c58b6fea4e6b49a7fccbc"}, + {file = "tree_sitter_json-0.24.8-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85cca779872f7278f3a74eb38533d34b9c4de4fd548615e3361fa64fe350ad0a"}, + {file = "tree_sitter_json-0.24.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:deeb45850dcc52990fbb52c80196492a099e3fa3512d928a390a91cf061068cc"}, + {file = "tree_sitter_json-0.24.8-cp39-abi3-win_amd64.whl", hash = "sha256:e4849a03cd7197267b2688a4506a90a13568a8e0e8588080bd0212fcb38974e3"}, + {file = "tree_sitter_json-0.24.8-cp39-abi3-win_arm64.whl", hash = "sha256:591e0096c882d12668b88f30d3ca6f85b9db3406910eaaab6afb6b17d65367dd"}, + {file = "tree_sitter_json-0.24.8.tar.gz", hash = "sha256:ca8486e52e2d261819311d35cf98656123d59008c3b7dcf91e61d2c0c6f3120e"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-markdown" +version = "0.3.2" +description = "Markdown grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2a0d60ee5185fbc20c6f3e7744348956a62f8bc9ae85b574251632e3c2220c77"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:0a72f199966380e18f668abb3e9d0a75569c8a292967deefc432282e253f9f84"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3555e5732223b030c8b5742fb565b4528566d96700ea7de9a2902e51fb91be21"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7fd68cbbccd917067696952773a553ef4d604017d9332b7a6f6a05549f1c0a3"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a693f0251f13fa925631fdc9e30f2435f5569d1b3b3d2c3d3b24060d3234f98a"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:507b9d99500dcbeefb069815b689c3dd36892375e878669f98125d0cd0a814a4"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-win_amd64.whl", hash = "sha256:a89a374920d648599d07036e0ec979f54fde684ddaee1bddf406339c51565cbc"}, + {file = "tree_sitter_markdown-0.3.2-cp39-abi3-win_arm64.whl", hash = "sha256:017e7c09c44861f35a4499564ecd0d97a25341905dc9d0dec2e6a38ee4e6b52d"}, + {file = "tree_sitter_markdown-0.3.2.tar.gz", hash = "sha256:64501234ae4ce5429551624e2fd675008cf86824bd8b9352223653e39218e753"}, +] + +[package.extras] +core = ["tree-sitter (>=0.23,<1.0)"] + +[[package]] +name = "tree-sitter-python" +version = "0.23.6" +description = "Python grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_python-0.23.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:28fbec8f74eeb2b30292d97715e60fac9ccf8a8091ce19b9d93e9b580ed280fb"}, + {file = "tree_sitter_python-0.23.6-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:680b710051b144fedf61c95197db0094f2245e82551bf7f0c501356333571f7a"}, + {file = "tree_sitter_python-0.23.6-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a9dcef55507b6567207e8ee0a6b053d0688019b47ff7f26edc1764b7f4dc0a4"}, + {file = "tree_sitter_python-0.23.6-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29dacdc0cd2f64e55e61d96c6906533ebb2791972bec988450c46cce60092f5d"}, + {file = "tree_sitter_python-0.23.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7e048733c36f564b379831689006801feb267d8194f9e793fbb395ef1723335d"}, + {file = "tree_sitter_python-0.23.6-cp39-abi3-win_amd64.whl", hash = "sha256:a24027248399fb41594b696f929f9956828ae7cc85596d9f775e6c239cd0c2be"}, + {file = "tree_sitter_python-0.23.6-cp39-abi3-win_arm64.whl", hash = "sha256:71334371bd73d5fe080aed39fbff49ed8efb9506edebe16795b0c7567ed6a272"}, + {file = "tree_sitter_python-0.23.6.tar.gz", hash = "sha256:354bfa0a2f9217431764a631516f85173e9711af2c13dbd796a8815acfe505d9"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-regex" +version = "0.24.3" +description = "Regex grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_regex-0.24.3-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:16ded552d0f43dda608cec078b4a63f1dfa53c793775ba1a1bb06b2539b94fff"}, + {file = "tree_sitter_regex-0.24.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:0a26bf77f7a8aa070299246eb3a29276030481ff380346c4085a97e448c34570"}, + {file = "tree_sitter_regex-0.24.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6abbf0708dbef6d70444bf9482528b39bae255ce59ed147dd1a731127e49a8da"}, + {file = "tree_sitter_regex-0.24.3-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb7134e1c954a18c321053f753da1c5aea9dc6d92e814796d34d03c4b76c012"}, + {file = "tree_sitter_regex-0.24.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:bf21ff69b8356d83b19ece6468ffe855d397eeeee1e34e8a11de0dc2be5ee896"}, + {file = "tree_sitter_regex-0.24.3-cp39-abi3-win_amd64.whl", hash = "sha256:7cb8f173054859a3d8b8f111833c638b1f1fef878fafb191e6974bbcaf5e930f"}, + {file = "tree_sitter_regex-0.24.3-cp39-abi3-win_arm64.whl", hash = "sha256:2eb9001e9ccb97d3d608e07f524335b0e5614abf67a004004c6c90abf0feb7cf"}, + {file = "tree_sitter_regex-0.24.3.tar.gz", hash = "sha256:58bb63f9e0ff01430da56ff158bddcb1b62a31f115abdf93cc6af76cc3aff86e"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-rust" +version = "0.23.2" +description = "Rust grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_rust-0.23.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b6b26a4c07ddc243f3701450ff34093b8e3b08f14d269db2d049c625d151677c"}, + {file = "tree_sitter_rust-0.23.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:c6224f608df559d75425e5ef428f635b9fb87d7aa8716444915ee67ec6955085"}, + {file = "tree_sitter_rust-0.23.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deced590a85ce848cda56f33728bad93b95827c1e3c736b707b24fb4280b3788"}, + {file = "tree_sitter_rust-0.23.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:540cf826932fe7cfd800361e368617e138c3d7914fad3b90786b7505af216be6"}, + {file = "tree_sitter_rust-0.23.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:880be40b220e87105b60db48c57cdd8019b5039b324afb1d643fa9c2fc187873"}, + {file = "tree_sitter_rust-0.23.2-cp39-abi3-win_amd64.whl", hash = "sha256:d8e0bea4fd76fc8b325247f3d1bb3dc2707db7dd3818b02c251efdea1b47909c"}, + {file = "tree_sitter_rust-0.23.2-cp39-abi3-win_arm64.whl", hash = "sha256:3ea49daa887ad59230758e7a96432193af4a2c7183781e1e85c35d4f8cb30b6b"}, + {file = "tree_sitter_rust-0.23.2.tar.gz", hash = "sha256:9088a0e0342d3de2749088811f5561994423cb10dab5ad3251003dffaa0a1bd1"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-sql" +version = "0.3.7" +description = "Tree-sitter Grammar for SQL" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_sql-0.3.7-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f3f8427328bd8b4ee02ab50d71bfc515937c037b8a03dcf54b8c98403d804269"}, + {file = "tree_sitter_sql-0.3.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:97ad55611f7d777b08a30d60150e1c44100ac2759a341b1cf1ffa2f97f20259e"}, + {file = "tree_sitter_sql-0.3.7-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa7beae1c2e841edc6de5a80d3ee6d401b579d9d27ce9553f2c569bef4b95b8f"}, + {file = "tree_sitter_sql-0.3.7-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5fc2daa8fc8d49265327ddaff0b5bbda5a6a0e37d05b157fdbcb2530f1e96e8"}, + {file = "tree_sitter_sql-0.3.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5f3c34121b625ee8f43e6ccffaca5205b206afa31592aedd1f078b4f6f4cb321"}, + {file = "tree_sitter_sql-0.3.7-cp38-abi3-win_amd64.whl", hash = "sha256:09e4af2b4c32b09e602c83f1e584e5f390901fce929fa7c3da2ddf416e30681e"}, + {file = "tree_sitter_sql-0.3.7-cp38-abi3-win_arm64.whl", hash = "sha256:e7b09235e5492ac8f71abaeb078e28dbfa94881998a5fbf22c659da49165054c"}, + {file = "tree_sitter_sql-0.3.7.tar.gz", hash = "sha256:5eb671ad597e6245d96aa44fd584c990d3eaffe80faddf941bfe8ebee6a8e2dd"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-toml" +version = "0.7.0" +description = "TOML grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_toml-0.7.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b9ae5c3e7c5b6bb05299dd73452ceafa7fa0687d5af3012332afa7757653b676"}, + {file = "tree_sitter_toml-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:18be09538e9775cddc0290392c4e2739de2201260af361473ca60b5c21f7bd22"}, + {file = "tree_sitter_toml-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a045e0acfcf91b7065066f7e51ea038ed7385c1e35e7e8fae18f252d3f8adb8c"}, + {file = "tree_sitter_toml-0.7.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a2f8cf9d73f07b6628093b35e5c5fbac039247e32cb075eaa5289a5914e73af"}, + {file = "tree_sitter_toml-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:860ffa4513b2dc3083d8e412bd815a350b0a9490624b37e7c8f6ed5c6f9ce63c"}, + {file = "tree_sitter_toml-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:2760a04f06937b01b1562a2135cd7e8207e399e73ef75bbebc77e37b1ad3b15d"}, + {file = "tree_sitter_toml-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:fd00fd8a51c65aa19c40539431cb1773d87c30af5757b4041fa6c229058420b4"}, + {file = "tree_sitter_toml-0.7.0.tar.gz", hash = "sha256:29e257612fa8f0c1fcbc4e7e08ddc561169f1725265302e64d81086354144a70"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-xml" +version = "0.7.0" +description = "XML & DTD grammars for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_xml-0.7.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cc3e516d4c1e0860fb22172c172148debb825ba638971bc48bad15b22e5b0bae"}, + {file = "tree_sitter_xml-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:0674fdf4cc386e4d323cb287d3b072663de0f20a9e9af5d5e09821aae56a9e5c"}, + {file = "tree_sitter_xml-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c0fe5f2d6cc09974c8375c8ea9b24909f493b5bf04aacdc4c694b5d2ae6b040"}, + {file = "tree_sitter_xml-0.7.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd3209516a4d84dff90bc91d2ad2ce246de8504cede4358849687fa8e71536e7"}, + {file = "tree_sitter_xml-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:87578e15fa55f44ecd9f331233b6f8a2cbde3546b354c830ecb862a632379455"}, + {file = "tree_sitter_xml-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:9ba2dafc6ce9feaf4ccc617d3aeea57f8e0ca05edad34953e788001ebff79133"}, + {file = "tree_sitter_xml-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:fc759f710a8fd7a01c23e2d7cb013679199045bea3dc0e5151650a11322aaf40"}, + {file = "tree_sitter_xml-0.7.0.tar.gz", hash = "sha256:ab0ff396f20230ad8483d968151ce0c35abe193eb023b20fbd8b8ce4cf9e9f61"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "tree-sitter-yaml" +version = "0.7.0" +description = "YAML grammar for tree-sitter" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e21553ac190ae05bf82796df8beb4d9158ba195b5846018cb36fbc3a35bd0679"}, + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:c022054f1f9b54201082ea83073a6c24c42d0436ad8ee99ff2574cba8f928c28"}, + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cd1725142f19e41c51d27c99cfc60780f596e069eb181cfa6433d993a19aa3d"}, + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d1b268378254f75bb27396d83c96d886ccbfcda6bd8c2778e94e3e1d2459085"}, + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:27c2e7f4f49ddf410003abbb82a7b00ec77ea263d8ef08dbce1a15d293eed2fd"}, + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:98dce0d6bc376f842cfb1d3c32512eea95b37e61cd2c87074bb4b05c999917c8"}, + {file = "tree_sitter_yaml-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:f0f8d8e05fa8e70f08d0f18a209d6026e171844f4ea7090e7c779b9c375b3a31"}, + {file = "tree_sitter_yaml-0.7.0.tar.gz", hash = "sha256:9c8bb17d9755c3b0e757260917240c0d19883cd3b59a5d74f205baa8bf8435a4"}, +] + +[package.extras] +core = ["tree-sitter (>=0.22,<1.0)"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2025.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, +] + +[[package]] +name = "uc-micro-py" +version = "1.0.3" +description = "Micro subset of unicode data files for linkify-it-py projects." +optional = false +python-versions = ">=3.7" +files = [ + {file = "uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a"}, + {file = "uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"}, +] + +[package.extras] +test = ["coverage", "pytest", "pytest-cov"] + +[[package]] +name = "virtualenv" +version = "20.29.1" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +files = [ + {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, + {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "zipp" +version = "3.21.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +files = [ + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.9,<3.14" +content-hash = "263f397eb0ab07b40e69b972e993f019bd5669719f1efad29a44a67cce1e3914" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..305e584 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,67 @@ +[tool.poetry] +name = "harlequin-mysql" +version = "1.1.0" +description = "A Harlequin adapter for MySQL." +authors = ["Ted Conbeer "] +license = "MIT" +readme = "README.md" +packages = [ + { include = "harlequin_mysql", from = "src" }, +] + +[tool.poetry.plugins."harlequin.adapter"] +mysql = "harlequin_mysql:HarlequinMySQLAdapter" + +[tool.poetry.dependencies] +python = ">=3.9,<3.14" +harlequin = ">=1.25.0,<3" +mysql-connector-python = "^9.1.0" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.6" +pytest = "^8" +mypy = "^1.11" +pre-commit = "^3.5.0" +importlib_metadata = { version = ">=4.6.0", python = "<3.10.0" } + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + + +[tool.ruff] +target-version = "py39" + +[tool.ruff.lint] +select = ["A", "B", "E", "F", "I"] + +[tool.mypy] +python_version = "3.9" +files = [ + "src/**/*.py", + "tests/**/*.py", +] +mypy_path = "src:stubs" + +show_column_numbers = true + +# show error messages from unrelated files +follow_imports = "normal" + +# be strict +disallow_untyped_calls = true +disallow_untyped_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +strict_optional = true + +warn_return_any = true +warn_no_return = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_unused_configs = true + +no_implicit_reexport = true +strict_equality = true diff --git a/src/harlequin_mysql/__init__.py b/src/harlequin_mysql/__init__.py new file mode 100644 index 0000000..5ef16a7 --- /dev/null +++ b/src/harlequin_mysql/__init__.py @@ -0,0 +1,3 @@ +from harlequin_mysql.adapter import HarlequinMySQLAdapter + +__all__ = ["HarlequinMySQLAdapter"] diff --git a/src/harlequin_mysql/adapter.py b/src/harlequin_mysql/adapter.py new file mode 100644 index 0000000..125a9bf --- /dev/null +++ b/src/harlequin_mysql/adapter.py @@ -0,0 +1,428 @@ +from __future__ import annotations + +import re +from contextlib import suppress +from typing import Any, Sequence + +from harlequin import ( + HarlequinAdapter, + HarlequinConnection, + HarlequinCursor, +) +from harlequin.autocomplete.completion import HarlequinCompletion +from harlequin.catalog import Catalog, CatalogItem +from harlequin.exception import ( + HarlequinConfigError, + HarlequinConnectionError, + HarlequinQueryError, +) +from mysql.connector import FieldType +from mysql.connector.cursor import MySQLCursor +from mysql.connector.errors import InternalError, PoolError +from mysql.connector.pooling import ( + MySQLConnectionPool, + PooledMySQLConnection, +) +from textual_fastdatatable.backend import AutoBackendType + +from harlequin_mysql.catalog import DatabaseCatalogItem +from harlequin_mysql.cli_options import MYSQLADAPTER_OPTIONS +from harlequin_mysql.completions import load_completions + +USE_DATABASE_PROG = re.compile( + r"\s*use\s+([^\\/?%*:|\"<>.]{1,64})", flags=re.IGNORECASE +) +QUERY_INTERRUPT_MSG = "1317 (70100): Query execution was interrupted" + + +class HarlequinMySQLCursor(HarlequinCursor): + def __init__( + self, + cur: MySQLCursor, + conn: PooledMySQLConnection, + harlequin_conn: HarlequinMySQLConnection, + *_: Any, + **__: Any, + ) -> None: + self.cur = cur + + # copy description in case the cursor is closed before columns() is called + assert cur.description is not None + self.description = cur.description.copy() + + self.conn = conn + self.harlequin_conn = harlequin_conn + self.connection_id = conn._cnx.connection_id + self._limit: int | None = None + + def columns(self) -> list[tuple[str, str]]: + return [(col[0], self._get_short_type(col[1])) for col in self.description] + + def set_limit(self, limit: int) -> "HarlequinMySQLCursor": + self._limit = limit + return self + + def fetchall(self) -> AutoBackendType: + try: + if self._limit is None: + results = self.cur.fetchall() + else: + results = self.cur.fetchmany(self._limit) + return results + except Exception as e: + if str(e) == QUERY_INTERRUPT_MSG: + return [] + else: + raise HarlequinQueryError( + msg=str(e), + title="Harlequin encountered an error while executing your query.", + ) from e + finally: + self.conn.consume_results() + self.cur.close() + self.conn.close() + if self.connection_id: + self.harlequin_conn._in_use_connections.discard(self.connection_id) + + @staticmethod + def _get_short_type(type_id: int) -> str: + mapping = { + FieldType.BIT: "010", + FieldType.BLOB: "0b", + FieldType.DATE: "d", + FieldType.DATETIME: "dt", + FieldType.DECIMAL: "#.#", + FieldType.DOUBLE: "#.#", + FieldType.ENUM: "enum", + FieldType.FLOAT: "#.#", + FieldType.GEOMETRY: "▽□", + FieldType.INT24: "###", + FieldType.JSON: "{}", + FieldType.LONG: "##", + FieldType.LONGLONG: "##", + FieldType.LONG_BLOB: "00b", + FieldType.MEDIUM_BLOB: "00b", + FieldType.NEWDATE: "d", + FieldType.NEWDECIMAL: "#.#", + FieldType.NULL: "∅", + FieldType.SET: "set", + FieldType.SHORT: "#", + FieldType.STRING: "s", + FieldType.TIME: "t", + FieldType.TIMESTAMP: "#ts", + FieldType.TINY: "#", + FieldType.TINY_BLOB: "b", + FieldType.VARCHAR: "s", + FieldType.VAR_STRING: "s", + FieldType.YEAR: "y", + } + return mapping.get(type_id, "?") + + +class HarlequinMySQLConnection(HarlequinConnection): + def __init__( + self, + conn_str: Sequence[str], + *_: Any, + init_message: str = "", + options: dict[str, Any], + ) -> None: + self.init_message = init_message + self._in_use_connections: set[int] = set() + try: + self._pool: MySQLConnectionPool = MySQLConnectionPool( + pool_name="harlequin", + pool_reset_session=False, + autocommit=True, + **options, + ) + except Exception as e: + raise HarlequinConnectionError( + msg=str(e), title="Harlequin could not connect to your database." + ) from e + + def safe_get_mysql_cursor( + self, buffered: bool = False + ) -> tuple[PooledMySQLConnection | None, MySQLCursor | None]: + """ + Return None if the connection pool is exhausted, to avoid getting + in an unrecoverable state. + """ + try: + conn = self._pool.get_connection() + except (InternalError, PoolError): + # if we're out of connections, we can't raise a query error, + # or we get in a state where we have cursors without fetched + # results, which requires a restart of Harlequin. Instead, + # just return None and silently fail (there isn't a sensible + # way to show an error to the user without aborting processing + # all the other cursors). + return None, None + + try: + cur: MySQLCursor = conn.cursor(buffered=buffered) + except InternalError: + # cursor has an unread result. Try to consume the results, + # and try again. + conn.consume_results() + cur = conn.cursor(buffered=buffered) + + return conn, cur + + def set_pool_config(self, **config: Any) -> None: + """ + Updates the config of the MySQL connection pool. + """ + self._pool.set_config(**config) + + def execute(self, query: str) -> HarlequinCursor | None: + retval: HarlequinCursor | None = None + + conn, cur = self.safe_get_mysql_cursor() + if conn is None or cur is None: + return None + else: + connection_id = conn._cnx.connection_id + if connection_id: + self._in_use_connections.add(connection_id) + + try: + cur.execute(query) + except Exception as e: + cur.close() + conn.close() + if connection_id: + self._in_use_connections.discard(connection_id) + if str(e) == QUERY_INTERRUPT_MSG: + return None + else: + raise HarlequinQueryError( + msg=str(e), + title="Harlequin encountered an error while executing your query.", + ) from e + else: + if cur.description is not None: + retval = HarlequinMySQLCursor(cur, conn=conn, harlequin_conn=self) + else: + cur.close() + conn.close() + if connection_id: + self._in_use_connections.discard(connection_id) + + # this is a hack to update all connections in the pool if the user + # changes the database for the active connection. + # it is impossible to check the database or other config + # of a connection with an open cursor, and we can't use a dedicated + # connection for user queries, since mysql only supports a single + # (unfetched) cursor per connection. + if match := USE_DATABASE_PROG.match(query): + new_db = match.group(1) + self.set_pool_config(database=new_db) + return retval + + def cancel(self) -> None: + # get a new cursor to execute the KILL statements + conn, cur = self.safe_get_mysql_cursor() + if conn is None or cur is None: + return None + + # loop through in-use connections and kill each of them + for connection_id in self._in_use_connections: + try: + cur.execute("KILL QUERY %s", (connection_id,)) + except BaseException: + continue + + cur.close() + conn.close() + self._in_use_connections = set() + + def close(self) -> None: + with suppress(PoolError): + self._pool._remove_connections() + + def get_catalog(self) -> Catalog: + databases = self._get_databases() + db_items: list[CatalogItem] = [ + DatabaseCatalogItem.from_label(label=db, connection=self) + for (db,) in databases + ] + return Catalog(items=db_items) + + def get_completions(self) -> list[HarlequinCompletion]: + return load_completions() + + def _get_databases(self) -> list[tuple[str]]: + conn, cur = self.safe_get_mysql_cursor(buffered=True) + if conn is None or cur is None: + raise HarlequinConnectionError( + title="Connection pool exhausted", + msg=( + "Connection pool exhausted. Try restarting Harlequin " + "with a larger pool or running fewer queries at once." + ), + ) + cur.execute( + """ + show databases + where `Database` not in ( + 'sys', 'information_schema', 'performance_schema', 'mysql' + ) + """ + ) + results: list[tuple[str]] = cur.fetchall() # type: ignore + cur.close() + conn.close() + return results + + def _get_relations(self, db_name: str) -> list[tuple[str, str]]: + conn, cur = self.safe_get_mysql_cursor(buffered=True) + if conn is None or cur is None: + raise HarlequinConnectionError( + title="Connection pool exhausted", + msg=( + "Connection pool exhausted. Try restarting Harlequin " + "with a larger pool or running fewer queries at once." + ), + ) + cur.execute( + f""" + select + table_name, + table_type + from information_schema.tables + where table_schema = '{db_name}' + and table_type != 'SYSTEM VIEW' + order by table_name asc + ;""" + ) + results: list[tuple[str, str]] = cur.fetchall() # type: ignore + cur.close() + conn.close() + return results + + def _get_columns(self, db_name: str, rel_name: str) -> list[tuple[str, str]]: + conn, cur = self.safe_get_mysql_cursor(buffered=True) + if conn is None or cur is None: + raise HarlequinConnectionError( + title="Connection pool exhausted", + msg=( + "Connection pool exhausted. Try restarting Harlequin " + "with a larger pool or running fewer queries at once." + ), + ) + cur.execute( + f""" + select column_name, data_type + from information_schema.columns + where + table_schema = '{db_name}' + and table_name = '{rel_name}' + and extra not like '%INVISIBLE%' + order by ordinal_position asc + ;""" + ) + results: list[tuple[str, str]] = cur.fetchall() # type: ignore + cur.close() + conn.close() + return results + + @staticmethod + def _short_column_type(info_schema_type: str) -> str: + mapping = { + "bigint": "###", + "binary": "010", + "blob": "0b", + "char": "c", + "datetime": "dt", + "decimal": "#.#", + "double": "#.#", + "enum": "enum", + "float": "#.#", + "int": "##", + "json": "{}", + "longblob": "00b", + "longtext": "ss", + "mediumblob": "00b", + "mediumint": "##", + "mediumtext": "s", + "set": "set", + "smallint": "#", + "text": "s", + "time": "t", + "timestamp": "ts", + "tinyint": "#", + "varbinary": "010", + "varchar": "s", + } + return mapping.get(info_schema_type, "?") + + +class HarlequinMySQLAdapter(HarlequinAdapter): + ADAPTER_OPTIONS = MYSQLADAPTER_OPTIONS + IMPLEMENTS_CANCEL = True + + def __init__( + self, + conn_str: Sequence[str], + host: str | None = None, + port: str | int | None = 3306, + unix_socket: str | None = None, + database: str | None = None, + user: str | None = None, + password: str | None = None, + password2: str | None = None, + password3: str | None = None, + connection_timeout: str | int | None = None, + ssl_ca: str | None = None, + ssl_cert: str | None = None, + ssl_disabled: str | bool | None = False, + ssl_key: str | None = None, + openid_token_file: str | None = None, + pool_size: str | int | None = 5, + **_: Any, + ) -> None: + if conn_str: + raise HarlequinConnectionError( + f"Cannot provide a DSN to the MySQL adapter. Got:\n{conn_str}" + ) + try: + self.options = { + "host": host, + "port": int(port) if port is not None else 3306, + "unix_socket": unix_socket, + "database": database, + "user": user, + "password": password, + "password2": password2, + "password3": password3, + "connection_timeout": int(connection_timeout) + if connection_timeout is not None + else None, + "ssl_ca": ssl_ca, + "ssl_cert": ssl_cert, + "ssl_disabled": ssl_disabled if ssl_disabled is not None else False, + "ssl_key": ssl_key, + "openid_token_file": openid_token_file, + "pool_size": int(pool_size) if pool_size is not None else 5, + } + except (ValueError, TypeError) as e: + raise HarlequinConfigError( + msg=f"MySQL adapter received bad config value: {e}", + title="Harlequin could not initialize the selected adapter.", + ) from e + + @property + def connection_id(self) -> str | None: + host = self.options.get("host", "") or "" + sock = self.options.get("unix_socket", "") or "" + host = host if host or sock else "127.0.0.1" + + port = self.options.get("port", 3306) + database = self.options.get("database", "") or "" + + return f"{host}{sock}:{port}/{database}" + + def connect(self) -> HarlequinMySQLConnection: + conn = HarlequinMySQLConnection(conn_str=tuple(), options=self.options) + return conn diff --git a/src/harlequin_mysql/catalog.py b/src/harlequin_mysql/catalog.py new file mode 100644 index 0000000..23556de --- /dev/null +++ b/src/harlequin_mysql/catalog.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING + +from harlequin.catalog import InteractiveCatalogItem + +from harlequin_mysql.interactions import ( + execute_drop_database_statement, + execute_drop_table_statement, + execute_drop_view_statement, + execute_use_statement, + insert_columns_at_cursor, + show_select_star, +) + +if TYPE_CHECKING: + from harlequin_mysql.adapter import HarlequinMySQLConnection + + +@dataclass +class ColumnCatalogItem(InteractiveCatalogItem["HarlequinMySQLConnection"]): + parent: "RelationCatalogItem" | None = None + + @classmethod + def from_parent( + cls, + parent: "RelationCatalogItem", + label: str, + type_label: str, + ) -> "ColumnCatalogItem": + column_qualified_identifier = f"{parent.qualified_identifier}.`{label}`" + column_query_name = f"`{label}`" + return cls( + qualified_identifier=column_qualified_identifier, + query_name=column_query_name, + label=label, + type_label=type_label, + connection=parent.connection, + parent=parent, + loaded=True, + ) + + +@dataclass +class RelationCatalogItem(InteractiveCatalogItem["HarlequinMySQLConnection"]): + INTERACTIONS = [ + ("Insert Columns at Cursor", insert_columns_at_cursor), + ("Preview Data", show_select_star), + ] + parent: "DatabaseCatalogItem" | None = None + + def fetch_children(self) -> list[ColumnCatalogItem]: + if self.parent is None or self.connection is None: + return [] + result = self.connection._get_columns(self.parent.label, self.label) + return [ + ColumnCatalogItem.from_parent( + parent=self, + label=column_name, + type_label=self.connection._short_column_type(column_type), + ) + for column_name, column_type in result + ] + + +class ViewCatalogItem(RelationCatalogItem): + INTERACTIONS = RelationCatalogItem.INTERACTIONS + [ + ("Drop View", execute_drop_view_statement), + ] + + @classmethod + def from_parent( + cls, + parent: "DatabaseCatalogItem", + label: str, + ) -> "ViewCatalogItem": + relation_query_name = f"`{parent.label}`.`{label}`" + relation_qualified_identifier = f"{parent.qualified_identifier}.`{label}`" + return cls( + qualified_identifier=relation_qualified_identifier, + query_name=relation_query_name, + label=label, + type_label="v", + connection=parent.connection, + parent=parent, + ) + + +class TableCatalogItem(RelationCatalogItem): + INTERACTIONS = RelationCatalogItem.INTERACTIONS + [ + ("Drop Table", execute_drop_table_statement), + ] + + @classmethod + def from_parent( + cls, + parent: "DatabaseCatalogItem", + label: str, + ) -> "TableCatalogItem": + relation_query_name = f"`{parent.label}`.`{label}`" + relation_qualified_identifier = f"{parent.qualified_identifier}.`{label}`" + return cls( + qualified_identifier=relation_qualified_identifier, + query_name=relation_query_name, + label=label, + type_label="t", + connection=parent.connection, + parent=parent, + ) + + +@dataclass +class DatabaseCatalogItem(InteractiveCatalogItem["HarlequinMySQLConnection"]): + INTERACTIONS = [ + ("Set Editor Context (USE)", execute_use_statement), + ("Drop Database", execute_drop_database_statement), + ] + + @classmethod + def from_label( + cls, label: str, connection: "HarlequinMySQLConnection" + ) -> "DatabaseCatalogItem": + database_identifier = f"`{label}`" + return cls( + qualified_identifier=database_identifier, + query_name=database_identifier, + label=label, + type_label="db", + connection=connection, + ) + + def fetch_children(self) -> list[RelationCatalogItem]: + if self.connection is None: + return [] + children: list[RelationCatalogItem] = [] + result = self.connection._get_relations(self.label) + for table_label, table_type in result: + if table_type == "VIEW": + children.append( + ViewCatalogItem.from_parent( + parent=self, + label=table_label, + ) + ) + else: + children.append( + TableCatalogItem.from_parent( + parent=self, + label=table_label, + ) + ) + + return children diff --git a/src/harlequin_mysql/cli_options.py b/src/harlequin_mysql/cli_options.py new file mode 100644 index 0000000..64b6eea --- /dev/null +++ b/src/harlequin_mysql/cli_options.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +from harlequin.options import ( + FlagOption, + PathOption, + TextOption, +) + + +def _int_validator(s: str | None) -> tuple[bool, str]: + if s is None: + return True, "" + try: + _ = int(s) + except ValueError: + return False, f"Cannot convert {s} to an int!" + else: + return True, "" + + +host = TextOption( + name="host", + description=("The host name or IP address of the MySQL server."), + short_decls=["-h"], + default="localhost", +) + + +port = TextOption( + name="port", + description=("The TCP/IP port of the MySQL server. Must be an integer."), + short_decls=["-p"], + default="3306", + validator=_int_validator, +) + + +unix_socket = TextOption( + name="unix_socket", + description=("The location of the Unix socket file."), +) + + +database = TextOption( + name="database", + description=("The database name to use when connecting with the MySQL server."), + short_decls=["-d", "-db"], + default="postgres", +) + + +user = TextOption( + name="user", + description=("The user name used to authenticate with the MySQL server."), + short_decls=["-u", "--username", "-U"], +) + + +password = TextOption( + name="password", + description=("The password to authenticate the user with the MySQL server."), + short_decls=["--password1"], +) + + +password2 = TextOption( + name="password2", + description=("For Multi-Factor Authentication (MFA); Added in 8.0.28."), +) + + +password3 = TextOption( + name="password3", + description=("For Multi-Factor Authentication (MFA); Added in 8.0.28."), +) + + +connect_timeout = TextOption( + name="connection_timeout", + description="Timeout for the TCP and Unix socket connections. Must be an integer.", + short_decls=["--connect_timeout"], + validator=_int_validator, +) + + +ssl_ca = PathOption( + name="ssl-ca", + description="File containing the SSL certificate authority.", + exists=True, + dir_okay=False, +) + +ssl_cert = PathOption( + name="ssl-cert", + description="File containing the SSL certificate file.", + exists=True, + dir_okay=False, + short_decls=["--sslcert"], +) + +ssl_disabled = FlagOption( + name="ssl-disabled", + description="True disables SSL/TLS usage.", +) + +ssl_key = PathOption( + name="ssl-key", + description="File containing the SSL key.", + exists=True, + dir_okay=False, + short_decls=["--sslkey"], +) + +openid_token_file = PathOption( + name="openid-token-file", + description="File containing the OpenID Token.", + exists=True, + dir_okay=False, + short_decls=["--oid"], +) + +pool_size = TextOption( + name="pool-size", + description=( + "The number of concurrent connections maintained by Harlequin. MySQL " + "only allows one cursor per connection, so this sets the number of queries " + "that can be executed at once in Harlequin." + ), + short_decls=["-n"], + default="5", + validator=_int_validator, +) + + +MYSQLADAPTER_OPTIONS = [ + host, + port, + unix_socket, + database, + user, + password, + password2, + password3, + connect_timeout, + ssl_ca, + ssl_cert, + ssl_disabled, + ssl_key, + openid_token_file, + pool_size, +] diff --git a/src/harlequin_mysql/completions.py b/src/harlequin_mysql/completions.py new file mode 100644 index 0000000..7fad79b --- /dev/null +++ b/src/harlequin_mysql/completions.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +import csv +import re +from pathlib import Path + +from harlequin import HarlequinCompletion + +WORD = re.compile(r"\w+") + + +def load_completions() -> list[HarlequinCompletion]: + completions: list[HarlequinCompletion] = [] + + keywords_path = Path(__file__).parent / "keywords.csv" + with keywords_path.open("r") as f: + reader = csv.reader(f, dialect="unix") + for name, reserved, removed in reader: + if removed == "False": + completions.append( + HarlequinCompletion( + label=name.lower(), + type_label="kw", + value=name.lower(), + priority=100 if reserved else 1000, + context=None, + ) + ) + + functions_path = Path(__file__).parent / "functions.tsv" + with functions_path.open("r") as f: + reader = csv.reader(f, dialect="unix", delimiter="\t") + for name, _, _, deprecated in reader: + if deprecated: + continue + for alias in name.split(", "): + if WORD.match(alias): + completions.append( + HarlequinCompletion( + label=alias.split("...")[0].split("(")[0].lower(), + type_label="fn", + value=alias.split("...")[0].split("(")[0].lower(), + priority=1000, + context=None, + ) + ) + + return completions diff --git a/src/harlequin_mysql/functions.tsv b/src/harlequin_mysql/functions.tsv new file mode 100644 index 0000000..363f9ed --- /dev/null +++ b/src/harlequin_mysql/functions.tsv @@ -0,0 +1,441 @@ +Name Description Introduced Deprecated +ABS() Return the absolute value +ACOS() Return the arc cosine +ADDDATE() Add time values (intervals) to a date value +ADDTIME() Add time +AES_DECRYPT() Decrypt using AES +AES_ENCRYPT() Encrypt using AES +AND, && Logical AND +ANY_VALUE() Suppress ONLY_FULL_GROUP_BY value rejection +ASCII() Return numeric value of left-most character +ASIN() Return the arc sine +asynchronous_connection_failover_add_managed() Add group member source server configuration information to a replication channel source list 8.0.23 +asynchronous_connection_failover_add_source() Add source server configuration information server to a replication channel source list 8.0.22 +asynchronous_connection_failover_delete_managed() Remove a managed group from a replication channel source list 8.0.23 +asynchronous_connection_failover_delete_source() Remove a source server from a replication channel source list 8.0.22 +asynchronous_connection_failover_reset() Remove all settings relating to group replication asynchronous failover 8.0.27 +ATAN() Return the arc tangent +ATAN2(), ATAN() Return the arc tangent of the two arguments +AVG() Return the average value of the argument +BENCHMARK() Repeatedly execute an expression +BETWEEN ... AND ... Whether a value is within a range of values +BIN() Return a string containing binary representation of a number +BIN_TO_UUID() Convert binary UUID to string +BINARY Cast a string to a binary string 8.0.27 +BIT_AND() Return bitwise AND +BIT_COUNT() Return the number of bits that are set +BIT_LENGTH() Return length of argument in bits +BIT_OR() Return bitwise OR +BIT_XOR() Return bitwise XOR +CAN_ACCESS_COLUMN() Internal use only +CAN_ACCESS_DATABASE() Internal use only +CAN_ACCESS_TABLE() Internal use only +CAN_ACCESS_USER() Internal use only 8.0.22 +CAN_ACCESS_VIEW() Internal use only +CASE Case operator +CAST() Cast a value as a certain type +CEIL() Return the smallest integer value not less than the argument +CEILING() Return the smallest integer value not less than the argument +CHAR() Return the character for each integer passed +CHAR_LENGTH() Return number of characters in argument +CHARACTER_LENGTH() Synonym for CHAR_LENGTH() +CHARSET() Return the character set of the argument +COALESCE() Return the first non-NULL argument +COERCIBILITY() Return the collation coercibility value of the string argument +COLLATION() Return the collation of the string argument +COMPRESS() Return result as a binary string +CONCAT() Return concatenated string +CONCAT_WS() Return concatenate with separator +CONNECTION_ID() Return the connection ID (thread ID) for the connection +CONV() Convert numbers between different number bases +CONVERT() Cast a value as a certain type +CONVERT_TZ() Convert from one time zone to another +COS() Return the cosine +COT() Return the cotangent +COUNT() Return a count of the number of rows returned +COUNT(DISTINCT) Return the count of a number of different values +CRC32() Compute a cyclic redundancy check value +CUME_DIST() Cumulative distribution value +CURDATE() Return the current date +CURRENT_DATE(), CURRENT_DATE Synonyms for CURDATE() +CURRENT_ROLE() Return the current active roles +CURRENT_TIME(), CURRENT_TIME Synonyms for CURTIME() +CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP Synonyms for NOW() +CURRENT_USER(), CURRENT_USER The authenticated user name and host name +CURTIME() Return the current time +DATABASE() Return the default (current) database name +DATE() Extract the date part of a date or datetime expression +DATE_ADD() Add time values (intervals) to a date value +DATE_FORMAT() Format date as specified +DATE_SUB() Subtract a time value (interval) from a date +DATEDIFF() Subtract two dates +DAY() Synonym for DAYOFMONTH() +DAYNAME() Return the name of the weekday +DAYOFMONTH() Return the day of the month (0-31) +DAYOFWEEK() Return the weekday index of the argument +DAYOFYEAR() Return the day of the year (1-366) +DEFAULT() Return the default value for a table column +DEGREES() Convert radians to degrees +DENSE_RANK() Rank of current row within its partition, without gaps +DIV Integer division +ELT() Return string at index number +EXP() Raise to the power of +EXPORT_SET() Return a string such that for every bit set in the value bits, you get an on string and for every unset bit, you get an off string +EXTRACT() Extract part of a date +ExtractValue() Extract a value from an XML string using XPath notation +FIELD() Index (position) of first argument in subsequent arguments +FIND_IN_SET() Index (position) of first argument within second argument +FIRST_VALUE() Value of argument from first row of window frame +FLOOR() Return the largest integer value not greater than the argument +FORMAT() Return a number formatted to specified number of decimal places +FORMAT_BYTES() Convert byte count to value with units 8.0.16 +FORMAT_PICO_TIME() Convert time in picoseconds to value with units 8.0.16 +FOUND_ROWS() For a SELECT with a LIMIT clause, the number of rows that would be returned were there no LIMIT clause +FROM_BASE64() Decode base64 encoded string and return result +FROM_DAYS() Convert a day number to a date +FROM_UNIXTIME() Format Unix timestamp as a date +GeomCollection() Construct geometry collection from geometries +GeometryCollection() Construct geometry collection from geometries +GET_DD_COLUMN_PRIVILEGES() Internal use only +GET_DD_CREATE_OPTIONS() Internal use only +GET_DD_INDEX_SUB_PART_LENGTH() Internal use only +GET_FORMAT() Return a date format string +GET_LOCK() Get a named lock +GREATEST() Return the largest argument +GROUP_CONCAT() Return a concatenated string +group_replication_disable_member_action() Disable member action for event specified 8.0.26 +group_replication_enable_member_action() Enable member action for event specified 8.0.26 +group_replication_get_communication_protocol() Get version of group replication communication protocol currently in use 8.0.16 +group_replication_get_write_concurrency() Get maximum number of consensus instances currently set for group 8.0.13 +group_replication_reset_member_actions() Reset all member actions to defaults and configuration version number to 1 8.0.26 +group_replication_set_as_primary() Make a specific group member the primary 8.0.29 +group_replication_set_communication_protocol() Set version for group replication communication protocol to use 8.0.16 +group_replication_set_write_concurrency() Set maximum number of consensus instances that can be executed in parallel 8.0.13 +group_replication_switch_to_multi_primary_mode() Changes the mode of a group running in single-primary mode to multi-primary mode 8.0.13 +group_replication_switch_to_single_primary_mode() Changes the mode of a group running in multi-primary mode to single-primary mode 8.0.13 +GROUPING() Distinguish super-aggregate ROLLUP rows from regular rows +GTID_SUBSET() Return true if all GTIDs in subset are also in set; otherwise false. +GTID_SUBTRACT() Return all GTIDs in set that are not in subset. +HEX() Hexadecimal representation of decimal or string value +HOUR() Extract the hour +ICU_VERSION() ICU library version +IF() If/else construct +IFNULL() Null if/else construct +IN() Whether a value is within a set of values +INET_ATON() Return the numeric value of an IP address +INET_NTOA() Return the IP address from a numeric value +INET6_ATON() Return the numeric value of an IPv6 address +INET6_NTOA() Return the IPv6 address from a numeric value +INSERT() Insert substring at specified position up to specified number of characters +INSTR() Return the index of the first occurrence of substring +INTERNAL_AUTO_INCREMENT() Internal use only +INTERNAL_AVG_ROW_LENGTH() Internal use only +INTERNAL_CHECK_TIME() Internal use only +INTERNAL_CHECKSUM() Internal use only +INTERNAL_DATA_FREE() Internal use only +INTERNAL_DATA_LENGTH() Internal use only +INTERNAL_DD_CHAR_LENGTH() Internal use only +INTERNAL_GET_COMMENT_OR_ERROR() Internal use only +INTERNAL_GET_ENABLED_ROLE_JSON() Internal use only 8.0.19 +INTERNAL_GET_HOSTNAME() Internal use only 8.0.19 +INTERNAL_GET_USERNAME() Internal use only 8.0.19 +INTERNAL_GET_VIEW_WARNING_OR_ERROR() Internal use only +INTERNAL_INDEX_COLUMN_CARDINALITY() Internal use only +INTERNAL_INDEX_LENGTH() Internal use only +INTERNAL_IS_ENABLED_ROLE() Internal use only 8.0.19 +INTERNAL_IS_MANDATORY_ROLE() Internal use only 8.0.19 +INTERNAL_KEYS_DISABLED() Internal use only +INTERNAL_MAX_DATA_LENGTH() Internal use only +INTERNAL_TABLE_ROWS() Internal use only +INTERNAL_UPDATE_TIME() Internal use only +INTERVAL() Return the index of the argument that is less than the first argument +IS Test a value against a boolean +IS_FREE_LOCK() Whether the named lock is free +IS_IPV4() Whether argument is an IPv4 address +IS_IPV4_COMPAT() Whether argument is an IPv4-compatible address +IS_IPV4_MAPPED() Whether argument is an IPv4-mapped address +IS_IPV6() Whether argument is an IPv6 address +IS NOT Test a value against a boolean +IS NOT NULL NOT NULL value test +IS NULL NULL value test +IS_USED_LOCK() Whether the named lock is in use; return connection identifier if true +IS_UUID() Whether argument is a valid UUID +ISNULL() Test whether the argument is NULL +JSON_ARRAY() Create JSON array +JSON_ARRAY_APPEND() Append data to JSON document +JSON_ARRAY_INSERT() Insert into JSON array +JSON_ARRAYAGG() Return result set as a single JSON array +JSON_CONTAINS() Whether JSON document contains specific object at path +JSON_CONTAINS_PATH() Whether JSON document contains any data at path +JSON_DEPTH() Maximum depth of JSON document +JSON_EXTRACT() Return data from JSON document +JSON_INSERT() Insert data into JSON document +JSON_KEYS() Array of keys from JSON document +JSON_LENGTH() Number of elements in JSON document +JSON_MERGE() Merge JSON documents, preserving duplicate keys. Deprecated synonym for JSON_MERGE_PRESERVE() Yes +JSON_MERGE_PATCH() Merge JSON documents, replacing values of duplicate keys +JSON_MERGE_PRESERVE() Merge JSON documents, preserving duplicate keys +JSON_OBJECT() Create JSON object +JSON_OBJECTAGG() Return result set as a single JSON object +JSON_OVERLAPS() Compares two JSON documents, returns TRUE (1) if these have any key-value pairs or array elements in common, otherwise FALSE (0) 8.0.17 +JSON_PRETTY() Print a JSON document in human-readable format +JSON_QUOTE() Quote JSON document +JSON_REMOVE() Remove data from JSON document +JSON_REPLACE() Replace values in JSON document +JSON_SCHEMA_VALID() Validate JSON document against JSON schema; returns TRUE/1 if document validates against schema, or FALSE/0 if it does not 8.0.17 +JSON_SCHEMA_VALIDATION_REPORT() Validate JSON document against JSON schema; returns report in JSON format on outcome on validation including success or failure and reasons for failure 8.0.17 +JSON_SEARCH() Path to value within JSON document +JSON_SET() Insert data into JSON document +JSON_STORAGE_FREE() Freed space within binary representation of JSON column value following partial update +JSON_STORAGE_SIZE() Space used for storage of binary representation of a JSON document +JSON_TABLE() Return data from a JSON expression as a relational table +JSON_TYPE() Type of JSON value +JSON_UNQUOTE() Unquote JSON value +JSON_VALID() Whether JSON value is valid +JSON_VALUE() Extract value from JSON document at location pointed to by path provided; return this value as VARCHAR(512) or specified type 8.0.21 +LAG() Value of argument from row lagging current row within partition +LAST_DAY Return the last day of the month for the argument +LAST_INSERT_ID() Value of the AUTOINCREMENT column for the last INSERT +LAST_VALUE() Value of argument from last row of window frame +LCASE() Synonym for LOWER() +LEAD() Value of argument from row leading current row within partition +LEAST() Return the smallest argument +LEFT() Return the leftmost number of characters as specified +LENGTH() Return the length of a string in bytes +LIKE Simple pattern matching +LineString() Construct LineString from Point values +LN() Return the natural logarithm of the argument +LOAD_FILE() Load the named file +LOCALTIME(), LOCALTIME Synonym for NOW() +LOCALTIMESTAMP, LOCALTIMESTAMP() Synonym for NOW() +LOCATE() Return the position of the first occurrence of substring +LOG() Return the natural logarithm of the first argument +LOG10() Return the base-10 logarithm of the argument +LOG2() Return the base-2 logarithm of the argument +LOWER() Return the argument in lowercase +LPAD() Return the string argument, left-padded with the specified string +LTRIM() Remove leading spaces +MAKE_SET() Return a set of comma-separated strings that have the corresponding bit in bits set +MAKEDATE() Create a date from the year and day of year +MAKETIME() Create time from hour, minute, second +MASTER_POS_WAIT() Block until the replica has read and applied all updates up to the specified position 8.0.26 +MATCH() Perform full-text search +MAX() Return the maximum value +MBRContains() Whether MBR of one geometry contains MBR of another +MBRCoveredBy() Whether one MBR is covered by another +MBRCovers() Whether one MBR covers another +MBRDisjoint() Whether MBRs of two geometries are disjoint +MBREquals() Whether MBRs of two geometries are equal +MBRIntersects() Whether MBRs of two geometries intersect +MBROverlaps() Whether MBRs of two geometries overlap +MBRTouches() Whether MBRs of two geometries touch +MBRWithin() Whether MBR of one geometry is within MBR of another +MD5() Calculate MD5 checksum +MEMBER OF() Returns true (1) if first operand matches any element of JSON array passed as second operand, otherwise returns false (0) 8.0.17 +MICROSECOND() Return the microseconds from argument +MID() Return a substring starting from the specified position +MIN() Return the minimum value +MINUTE() Return the minute from the argument +MOD() Return the remainder +MONTH() Return the month from the date passed +MONTHNAME() Return the name of the month +MultiLineString() Contruct MultiLineString from LineString values +MultiPoint() Construct MultiPoint from Point values +MultiPolygon() Construct MultiPolygon from Polygon values +NAME_CONST() Cause the column to have the given name +NOT, ! Negates value +NOT BETWEEN ... AND ... Whether a value is not within a range of values +NOT IN() Whether a value is not within a set of values +NOT LIKE Negation of simple pattern matching +NOT REGEXP Negation of REGEXP +NOW() Return the current date and time +NTH_VALUE() Value of argument from N-th row of window frame +NTILE() Bucket number of current row within its partition. +NULLIF() Return NULL if expr1 = expr2 +OCT() Return a string containing octal representation of a number +OCTET_LENGTH() Synonym for LENGTH() +OR, || Logical OR +ORD() Return character code for leftmost character of the argument +PERCENT_RANK() Percentage rank value +PERIOD_ADD() Add a period to a year-month +PERIOD_DIFF() Return the number of months between periods +PI() Return the value of pi +Point() Construct Point from coordinates +Polygon() Construct Polygon from LineString arguments +POSITION() Synonym for LOCATE() +POW() Return the argument raised to the specified power +POWER() Return the argument raised to the specified power +PS_CURRENT_THREAD_ID() Performance Schema thread ID for current thread 8.0.16 +PS_THREAD_ID() Performance Schema thread ID for given thread 8.0.16 +QUARTER() Return the quarter from a date argument +QUOTE() Escape the argument for use in an SQL statement +RADIANS() Return argument converted to radians +RAND() Return a random floating-point value +RANDOM_BYTES() Return a random byte vector +RANK() Rank of current row within its partition, with gaps +REGEXP Whether string matches regular expression +REGEXP_INSTR() Starting index of substring matching regular expression +REGEXP_LIKE() Whether string matches regular expression +REGEXP_REPLACE() Replace substrings matching regular expression +REGEXP_SUBSTR() Return substring matching regular expression +RELEASE_ALL_LOCKS() Release all current named locks +RELEASE_LOCK() Release the named lock +REPEAT() Repeat a string the specified number of times +REPLACE() Replace occurrences of a specified string +REVERSE() Reverse the characters in a string +RIGHT() Return the specified rightmost number of characters +RLIKE Whether string matches regular expression +ROLES_GRAPHML() Return a GraphML document representing memory role subgraphs +ROUND() Round the argument +ROW_COUNT() The number of rows updated +ROW_NUMBER() Number of current row within its partition +RPAD() Append string the specified number of times +RTRIM() Remove trailing spaces +SCHEMA() Synonym for DATABASE() +SEC_TO_TIME() Converts seconds to 'hh:mm:ss' format +SECOND() Return the second (0-59) +SESSION_USER() Synonym for USER() +SHA1(), SHA() Calculate an SHA-1 160-bit checksum +SHA2() Calculate an SHA-2 checksum +SIGN() Return the sign of the argument +SIN() Return the sine of the argument +SLEEP() Sleep for a number of seconds +SOUNDEX() Return a soundex string +SOUNDS LIKE Compare sounds +SOURCE_POS_WAIT() Block until the replica has read and applied all updates up to the specified position 8.0.26 +SPACE() Return a string of the specified number of spaces +SQRT() Return the square root of the argument +ST_Area() Return Polygon or MultiPolygon area +ST_AsBinary(), ST_AsWKB() Convert from internal geometry format to WKB +ST_AsGeoJSON() Generate GeoJSON object from geometry +ST_AsText(), ST_AsWKT() Convert from internal geometry format to WKT +ST_Buffer() Return geometry of points within given distance from geometry +ST_Buffer_Strategy() Produce strategy option for ST_Buffer() +ST_Centroid() Return centroid as a point +ST_Collect() Aggregate spatial values into collection 8.0.24 +ST_Contains() Whether one geometry contains another +ST_ConvexHull() Return convex hull of geometry +ST_Crosses() Whether one geometry crosses another +ST_Difference() Return point set difference of two geometries +ST_Dimension() Dimension of geometry +ST_Disjoint() Whether one geometry is disjoint from another +ST_Distance() The distance of one geometry from another +ST_Distance_Sphere() Minimum distance on earth between two geometries +ST_EndPoint() End Point of LineString +ST_Envelope() Return MBR of geometry +ST_Equals() Whether one geometry is equal to another +ST_ExteriorRing() Return exterior ring of Polygon +ST_FrechetDistance() The discrete Fréchet distance of one geometry from another 8.0.23 +ST_GeoHash() Produce a geohash value +ST_GeomCollFromText(), ST_GeometryCollectionFromText(), ST_GeomCollFromTxt() Return geometry collection from WKT +ST_GeomCollFromWKB(), ST_GeometryCollectionFromWKB() Return geometry collection from WKB +ST_GeometryN() Return N-th geometry from geometry collection +ST_GeometryType() Return name of geometry type +ST_GeomFromGeoJSON() Generate geometry from GeoJSON object +ST_GeomFromText(), ST_GeometryFromText() Return geometry from WKT +ST_GeomFromWKB(), ST_GeometryFromWKB() Return geometry from WKB +ST_HausdorffDistance() The discrete Hausdorff distance of one geometry from another 8.0.23 +ST_InteriorRingN() Return N-th interior ring of Polygon +ST_Intersection() Return point set intersection of two geometries +ST_Intersects() Whether one geometry intersects another +ST_IsClosed() Whether a geometry is closed and simple +ST_IsEmpty() Whether a geometry is empty +ST_IsSimple() Whether a geometry is simple +ST_IsValid() Whether a geometry is valid +ST_LatFromGeoHash() Return latitude from geohash value +ST_Latitude() Return latitude of Point 8.0.12 +ST_Length() Return length of LineString +ST_LineFromText(), ST_LineStringFromText() Construct LineString from WKT +ST_LineFromWKB(), ST_LineStringFromWKB() Construct LineString from WKB +ST_LineInterpolatePoint() The point a given percentage along a LineString 8.0.24 +ST_LineInterpolatePoints() The points a given percentage along a LineString 8.0.24 +ST_LongFromGeoHash() Return longitude from geohash value +ST_Longitude() Return longitude of Point 8.0.12 +ST_MakeEnvelope() Rectangle around two points +ST_MLineFromText(), ST_MultiLineStringFromText() Construct MultiLineString from WKT +ST_MLineFromWKB(), ST_MultiLineStringFromWKB() Construct MultiLineString from WKB +ST_MPointFromText(), ST_MultiPointFromText() Construct MultiPoint from WKT +ST_MPointFromWKB(), ST_MultiPointFromWKB() Construct MultiPoint from WKB +ST_MPolyFromText(), ST_MultiPolygonFromText() Construct MultiPolygon from WKT +ST_MPolyFromWKB(), ST_MultiPolygonFromWKB() Construct MultiPolygon from WKB +ST_NumGeometries() Return number of geometries in geometry collection +ST_NumInteriorRing(), ST_NumInteriorRings() Return number of interior rings in Polygon +ST_NumPoints() Return number of points in LineString +ST_Overlaps() Whether one geometry overlaps another +ST_PointAtDistance() The point a given distance along a LineString 8.0.24 +ST_PointFromGeoHash() Convert geohash value to POINT value +ST_PointFromText() Construct Point from WKT +ST_PointFromWKB() Construct Point from WKB +ST_PointN() Return N-th point from LineString +ST_PolyFromText(), ST_PolygonFromText() Construct Polygon from WKT +ST_PolyFromWKB(), ST_PolygonFromWKB() Construct Polygon from WKB +ST_Simplify() Return simplified geometry +ST_SRID() Return spatial reference system ID for geometry +ST_StartPoint() Start Point of LineString +ST_SwapXY() Return argument with X/Y coordinates swapped +ST_SymDifference() Return point set symmetric difference of two geometries +ST_Touches() Whether one geometry touches another +ST_Transform() Transform coordinates of geometry 8.0.13 +ST_Union() Return point set union of two geometries +ST_Validate() Return validated geometry +ST_Within() Whether one geometry is within another +ST_X() Return X coordinate of Point +ST_Y() Return Y coordinate of Point +STATEMENT_DIGEST() Compute statement digest hash value +STATEMENT_DIGEST_TEXT() Compute normalized statement digest +STD() Return the population standard deviation +STDDEV() Return the population standard deviation +STDDEV_POP() Return the population standard deviation +STDDEV_SAMP() Return the sample standard deviation +STR_TO_DATE() Convert a string to a date +STRCMP() Compare two strings +SUBDATE() Synonym for DATE_SUB() when invoked with three arguments +SUBSTR() Return the substring as specified +SUBSTRING() Return the substring as specified +SUBSTRING_INDEX() Return a substring from a string before the specified number of occurrences of the delimiter +SUBTIME() Subtract times +SUM() Return the sum +SYSDATE() Return the time at which the function executes +SYSTEM_USER() Synonym for USER() +TAN() Return the tangent of the argument +TIME() Extract the time portion of the expression passed +TIME_FORMAT() Format as time +TIME_TO_SEC() Return the argument converted to seconds +TIMEDIFF() Subtract time +TIMESTAMP() With a single argument, this function returns the date or datetime expression; with two arguments, the sum of the arguments +TIMESTAMPADD() Add an interval to a datetime expression +TIMESTAMPDIFF() Return the difference of two datetime expressions, using the units specified +TO_BASE64() Return the argument converted to a base-64 string +TO_DAYS() Return the date argument converted to days +TO_SECONDS() Return the date or datetime argument converted to seconds since Year 0 +TRIM() Remove leading and trailing spaces +TRUNCATE() Truncate to specified number of decimal places +UCASE() Synonym for UPPER() +UNCOMPRESS() Uncompress a string compressed +UNCOMPRESSED_LENGTH() Return the length of a string before compression +UNHEX() Return a string containing hex representation of a number +UNIX_TIMESTAMP() Return a Unix timestamp +UpdateXML() Return replaced XML fragment +UPPER() Convert to uppercase +USER() The user name and host name provided by the client +UTC_DATE() Return the current UTC date +UTC_TIME() Return the current UTC time +UTC_TIMESTAMP() Return the current UTC date and time +UUID() Return a Universal Unique Identifier (UUID) +UUID_SHORT() Return an integer-valued universal identifier +UUID_TO_BIN() Convert string UUID to binary +VALIDATE_PASSWORD_STRENGTH() Determine strength of password +VALUES() Define the values to be used during an INSERT +VAR_POP() Return the population standard variance +VAR_SAMP() Return the sample variance +VARIANCE() Return the population standard variance +VERSION() Return a string that indicates the MySQL server version +WAIT_FOR_EXECUTED_GTID_SET() Wait until the given GTIDs have executed on the replica. +WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() Use WAIT_FOR_EXECUTED_GTID_SET(). 8.0.18 +WEEK() Return the week number +WEEKDAY() Return the weekday index +WEEKOFYEAR() Return the calendar week of the date (1-53) +WEIGHT_STRING() Return the weight string for a string +XOR Logical XOR +YEAR() Return the year +YEARWEEK() Return the year and week \ No newline at end of file diff --git a/src/harlequin_mysql/interactions.py b/src/harlequin_mysql/interactions.py new file mode 100644 index 0000000..414fd71 --- /dev/null +++ b/src/harlequin_mysql/interactions.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +from textwrap import dedent +from typing import TYPE_CHECKING, Literal, Sequence + +from harlequin.catalog import CatalogItem +from harlequin.exception import HarlequinQueryError + +if TYPE_CHECKING: + from harlequin.driver import HarlequinDriver + + from harlequin_mysql.catalog import ( + ColumnCatalogItem, + DatabaseCatalogItem, + RelationCatalogItem, + ) + + +def execute_use_statement( + item: "DatabaseCatalogItem", + driver: "HarlequinDriver", +) -> None: + if item.connection is None: + return + try: + item.connection.execute(f"use {item.label}") + except HarlequinQueryError: + driver.notify("Could not switch context", severity="error") + raise + else: + driver.notify(f"Editor context switched to {item.label}") + + +def execute_drop_database_statement( + item: "DatabaseCatalogItem", + driver: "HarlequinDriver", +) -> None: + def _drop_database() -> None: + if item.connection is None: + return + try: + item.connection.execute(f"drop database {item.qualified_identifier}") + except HarlequinQueryError: + driver.notify(f"Could not drop database {item.label}", severity="error") + raise + else: + driver.notify(f"Dropped database {item.label}") + driver.refresh_catalog() + + if item.children or item.fetch_children(): + driver.confirm_and_execute(callback=_drop_database) + else: + _drop_database() + + +def execute_drop_relation_statement( + item: "RelationCatalogItem", + driver: "HarlequinDriver", + relation_type: Literal["view", "table", "foreign table"], +) -> None: + def _drop_relation() -> None: + if item.connection is None: + return + try: + item.connection.execute(f"drop {relation_type} {item.qualified_identifier}") + except HarlequinQueryError: + driver.notify( + f"Could not drop {relation_type} {item.label}", severity="error" + ) + raise + else: + driver.notify(f"Dropped {relation_type} {item.label}") + driver.refresh_catalog() + + driver.confirm_and_execute(callback=_drop_relation) + + +def execute_drop_table_statement( + item: "RelationCatalogItem", driver: "HarlequinDriver" +) -> None: + execute_drop_relation_statement(item=item, driver=driver, relation_type="table") + + +def execute_drop_view_statement( + item: "RelationCatalogItem", driver: "HarlequinDriver" +) -> None: + execute_drop_relation_statement(item=item, driver=driver, relation_type="view") + + +def show_select_star( + item: "RelationCatalogItem", + driver: "HarlequinDriver", +) -> None: + driver.insert_text_in_new_buffer( + dedent( + f""" + select * + from {item.qualified_identifier} + limit 100 + """.strip("\n") + ) + ) + + +def insert_columns_at_cursor( + item: "RelationCatalogItem", + driver: "HarlequinDriver", +) -> None: + if item.loaded: + cols: Sequence["CatalogItem" | "ColumnCatalogItem"] = item.children + else: + cols = item.fetch_children() + driver.insert_text_at_selection(text=",\n".join(c.query_name for c in cols)) diff --git a/src/harlequin_mysql/keywords.csv b/src/harlequin_mysql/keywords.csv new file mode 100644 index 0000000..47737c7 --- /dev/null +++ b/src/harlequin_mysql/keywords.csv @@ -0,0 +1,892 @@ +ACCESSIBLE,False,False +ACCOUNT,False,False +ACTION,False,False +ACTIVE,False,False +ADD,False,False +ADMIN,False,False +AFTER,False,False +AGAINST,False,False +AGGREGATE,False,False +ALGORITHM,False,False +ALL,False,False +ALTER,False,False +ALWAYS,False,False +ANALYSE,False,True +ANALYZE,False,False +AND,False,False +ANY,False,False +ARRAY,False,False +AS,False,False +ASC,False,False +ASCII,False,False +ASENSITIVE,False,False +AT,False,False +ATTRIBUTE,False,False +AUTHENTICATION,False,False +AUTOEXTEND_SIZE,False,False +AUTO_INCREMENT,False,False +AVG,False,False +AVG_ROW_LENGTH,False,False +BACKUP,False,False +BEFORE,False,False +BEGIN,False,False +BETWEEN,False,False +BIGINT,False,False +BINARY,False,False +BINLOG,False,False +BIT,False,False +BLOB,False,False +BLOCK,False,False +BOOL,False,False +BOOLEAN,False,False +BOTH,False,False +BTREE,False,False +BUCKETS,False,False +BULK,False,False +BY,False,False +BYTE,False,False +CACHE,False,False +CALL,False,False +CASCADE,False,False +CASCADED,False,False +CASE,False,False +CATALOG_NAME,False,False +CHAIN,False,False +CHALLENGE_RESPONSE,False,False +CHANGE,False,False +CHANGED,False,False +CHANNEL,False,False +CHAR,False,False +CHARACTER,False,False +CHARSET,False,False +CHECK,False,False +CHECKSUM,False,False +CIPHER,False,False +CLASS_ORIGIN,False,False +CLIENT,False,False +CLONE,False,False +CLOSE,False,False +COALESCE,False,False +CODE,False,False +COLLATE,False,False +COLLATION,False,False +COLUMN,False,False +COLUMNS,False,False +COLUMN_FORMAT,False,False +COLUMN_NAME,False,False +COMMENT,False,False +COMMIT,False,False +COMMITTED,False,False +COMPACT,False,False +COMPLETION,False,False +COMPONENT,False,False +COMPRESSED,False,False +COMPRESSION,False,False +CONCURRENT,False,False +CONDITION,False,False +CONNECTION,False,False +CONSISTENT,False,False +CONSTRAINT,False,False +CONSTRAINT_CATALOG,False,False +CONSTRAINT_NAME,False,False +CONSTRAINT_SCHEMA,False,False +CONTAINS,False,False +CONTEXT,False,False +CONTINUE,False,False +CONVERT,False,False +CPU,False,False +CREATE,False,False +CROSS,False,False +CUBE,False,False +CUME_DIST,False,False +CURRENT,False,False +CURRENT_DATE,False,False +CURRENT_TIME,False,False +CURRENT_TIMESTAMP,False,False +CURRENT_USER,False,False +CURSOR,False,False +CURSOR_NAME,False,False +DATA,False,False +DATABASE,False,False +DATABASES,False,False +DATAFILE,False,False +DATE,False,False +DATETIME,False,False +DAY,False,False +DAY_HOUR,False,False +DAY_MICROSECOND,False,False +DAY_MINUTE,False,False +DAY_SECOND,False,False +DEALLOCATE,False,False +DEC,False,False +DECIMAL,False,False +DECLARE,False,False +DEFAULT,False,False +DEFAULT_AUTH,False,False +DEFINER,False,False +DEFINITION,False,False +DELAYED,False,False +DELAY_KEY_WRITE,False,False +DELETE,False,False +DENSE_RANK,False,False +DESC,False,False +DESCRIBE,False,False +DESCRIPTION,False,False +DES_KEY_FILE,False,True +DETERMINISTIC,False,False +DIAGNOSTICS,False,False +DIRECTORY,False,False +DISABLE,False,False +DISCARD,False,False +DISK,False,False +DISTINCT,False,False +DISTINCTROW,False,False +DIV,False,False +DO,False,False +DOUBLE,False,False +DROP,False,False +DUAL,False,False +DUMPFILE,False,False +DUPLICATE,False,False +DYNAMIC,False,False +EACH,False,False +ELSE,False,False +ELSEIF,False,False +EMPTY,False,False +ENABLE,False,False +ENCLOSED,False,False +ENCRYPTION,False,False +END,False,False +ENDS,False,False +ENFORCED,False,False +ENGINE,False,False +ENGINES,False,False +ENGINE_ATTRIBUTE,False,False +ENUM,False,False +ERROR,False,False +ERRORS,False,False +ESCAPE,False,False +ESCAPED,False,False +EVENT,False,False +EVENTS,False,False +EVERY,False,False +EXCEPT,False,False +EXCHANGE,False,False +EXCLUDE,False,False +EXECUTE,False,False +EXISTS,False,False +EXIT,False,False +EXPANSION,False,False +EXPIRE,False,False +EXPLAIN,False,False +EXPORT,False,False +EXTENDED,False,False +EXTENT_SIZE,False,False +FACTOR,False,False +FAILED_LOGIN_ATTEMPTS,False,False +FALSE,False,False +FAST,False,False +FAULTS,False,False +FETCH,False,False +FIELDS,False,False +FILE,False,False +FILE_BLOCK_SIZE,False,False +FILTER,False,False +FINISH,False,False +FIRST,False,False +FIRST_VALUE,False,False +FIXED,False,False +FLOAT,False,False +FLOAT4,False,False +FLOAT8,False,False +FLUSH,False,False +FOLLOWING,False,False +FOLLOWS,False,False +FOR,False,False +FORCE,False,False +FOREIGN,False,False +FORMAT,False,False +FOUND,False,False +FROM,False,False +FULL,False,False +FULLTEXT,False,False +FUNCTION,False,False +GENERAL,False,False +GENERATE,False,False +GENERATED,False,False +GEOMCOLLECTION,False,False +GEOMETRY,False,False +GEOMETRYCOLLECTION,False,False +GET,False,False +GET_FORMAT,False,False +GET_MASTER_PUBLIC_KEY,False,False +GET_SOURCE_PUBLIC_KEY,False,False +GLOBAL,False,False +GRANT,False,False +GRANTS,False,False +GROUP,False,False +GROUPING,False,False +GROUPS,False,False +GROUP_REPLICATION,False,False +GTID_ONLY,False,False +HANDLER,False,False +HASH,False,False +HAVING,False,False +HELP,False,False +HIGH_PRIORITY,False,False +HISTOGRAM,False,False +HISTORY,False,False +HOST,False,False +HOSTS,False,False +HOUR,False,False +HOUR_MICROSECOND,False,False +HOUR_MINUTE,False,False +HOUR_SECOND,False,False +IDENTIFIED,False,False +IF,False,False +IGNORE,False,False +IGNORE_SERVER_IDS,False,False +IMPORT,False,False +IN,False,False +INACTIVE,False,False +INDEX,False,False +INDEXES,False,False +INFILE,False,False +INITIAL,False,False +INITIAL_SIZE,False,False +INITIATE,False,False +INNER,False,False +INOUT,False,False +INSENSITIVE,False,False +INSERT,False,False +INSERT_METHOD,False,False +INSTALL,False,False +INSTANCE,False,False +INT,False,False +INT1,False,False +INT2,False,False +INT3,False,False +INT4,False,False +INT8,False,False +INTEGER,False,False +INTERSECT,False,False +INTERVAL,False,False +INTO,False,False +INVISIBLE,False,False +INVOKER,False,False +IO,False,False +IO_AFTER_GTIDS,False,False +IO_BEFORE_GTIDS,False,False +IO_THREAD,False,False +IPC,False,False +IS,False,False +ISOLATION,False,False +ISSUER,False,False +ITERATE,False,False +JOIN,False,False +JSON,False,False +JSON_TABLE,False,False +JSON_VALUE,False,False +KEY,False,False +KEYRING,False,False +KEYS,False,False +KEY_BLOCK_SIZE,False,False +KILL,False,False +LAG,False,False +LANGUAGE,False,False +LAST,False,False +LAST_VALUE,False,False +LATERAL,False,False +LEAD,False,False +LEADING,False,False +LEAVE,False,False +LEAVES,False,False +LEFT,False,False +LESS,False,False +LEVEL,False,False +LIKE,False,False +LIMIT,False,False +LINEAR,False,False +LINES,False,False +LINESTRING,False,False +LIST,False,False +LOAD,False,False +LOCAL,False,False +LOCALTIME,False,False +LOCALTIMESTAMP,False,False +LOCK,False,False +LOCKED,False,False +LOCKS,False,False +LOGFILE,False,False +LOGS,False,False +LONG,False,False +LONGBLOB,False,False +LONGTEXT,False,False +LOOP,False,False +LOW_PRIORITY,False,False +MASTER,False,False +MASTER_AUTO_POSITION,False,False +MASTER_BIND,False,False +MASTER_COMPRESSION_ALGORITHMS,False,False +MASTER_CONNECT_RETRY,False,False +MASTER_DELAY,False,False +MASTER_HEARTBEAT_PERIOD,False,False +MASTER_HOST,False,False +MASTER_LOG_FILE,False,False +MASTER_LOG_POS,False,False +MASTER_PASSWORD,False,False +MASTER_PORT,False,False +MASTER_PUBLIC_KEY_PATH,False,False +MASTER_RETRY_COUNT,False,False +MASTER_SERVER_ID,False,True +MASTER_SSL,False,False +MASTER_SSL_CA,False,False +MASTER_SSL_CAPATH,False,False +MASTER_SSL_CERT,False,False +MASTER_SSL_CIPHER,False,False +MASTER_SSL_CRL,False,False +MASTER_SSL_CRLPATH,False,False +MASTER_SSL_KEY,False,False +MASTER_SSL_VERIFY_SERVER_CERT,False,False +MASTER_TLS_CIPHERSUITES,False,False +MASTER_TLS_VERSION,False,False +MASTER_USER,False,False +MASTER_ZSTD_COMPRESSION_LEVEL,False,False +MATCH,False,False +MAXVALUE,False,False +MAX_CONNECTIONS_PER_HOUR,False,False +MAX_QUERIES_PER_HOUR,False,False +MAX_ROWS,False,False +MAX_SIZE,False,False +MAX_UPDATES_PER_HOUR,False,False +MAX_USER_CONNECTIONS,False,False +MEDIUM,False,False +MEDIUMBLOB,False,False +MEDIUMINT,False,False +MEDIUMTEXT,False,False +MEMBER,False,False +MEMORY,False,False +MERGE,False,False +MESSAGE_TEXT,False,False +MICROSECOND,False,False +MIDDLEINT,False,False +MIGRATE,False,False +MINUTE,False,False +MINUTE_MICROSECOND,False,False +MINUTE_SECOND,False,False +MIN_ROWS,False,False +MOD,False,False +MODE,False,False +MODIFIES,False,False +MODIFY,False,False +MONTH,False,False +MULTILINESTRING,False,False +MULTIPOINT,False,False +MULTIPOLYGON,False,False +MUTEX,False,False +MYSQL_ERRNO,False,False +NAME,False,False +NAMES,False,False +NATIONAL,False,False +NATURAL,False,False +NCHAR,False,False +NDB,False,False +NDBCLUSTER,False,False +NESTED,False,False +NETWORK_NAMESPACE,False,False +NEVER,False,False +NEW,False,False +NEXT,False,False +NO,False,False +NODEGROUP,False,False +NONE,False,False +NOT,False,False +NOWAIT,False,False +NO_WAIT,False,False +NO_WRITE_TO_BINLOG,False,False +NTH_VALUE,False,False +NTILE,False,False +NULL,False,False +NULLS,False,False +NUMBER,False,False +NUMERIC,False,False +NVARCHAR,False,False +OF,False,False +OFF,False,False +OFFSET,False,False +OJ,False,False +OLD,False,False +ON,False,False +ONE,False,False +ONLY,False,False +OPEN,False,False +OPTIMIZE,False,False +OPTIMIZER_COSTS,False,False +OPTION,False,False +OPTIONAL,False,False +OPTIONALLY,False,False +OPTIONS,False,False +OR,False,False +ORDER,False,False +ORDINALITY,False,False +ORGANIZATION,False,False +OTHERS,False,False +OUT,False,False +OUTER,False,False +OUTFILE,False,False +OVER,False,False +OWNER,False,False +PACK_KEYS,False,False +PAGE,False,False +PARSER,False,False +PARTIAL,False,False +PARTITION,False,False +PARTITIONING,False,False +PARTITIONS,False,False +PASSWORD,False,False +PASSWORD_LOCK_TIME,False,False +PATH,False,False +PERCENT_RANK,False,False +PERSIST,False,False +PERSIST_ONLY,False,False +PHASE,False,False +PLUGIN,False,False +PLUGINS,False,False +PLUGIN_DIR,False,False +POINT,False,False +POLYGON,False,False +PORT,False,False +PRECEDES,False,False +PRECEDING,False,False +PRECISION,False,False +PREPARE,False,False +PRESERVE,False,False +PREV,False,False +PRIMARY,False,False +PRIVILEGES,False,False +PRIVILEGE_CHECKS_USER,False,False +PROCEDURE,False,False +PROCESS,False,False +PROCESSLIST,False,False +PROFILE,False,False +PROFILES,False,False +PROXY,False,False +PURGE,False,False +QUARTER,False,False +QUERY,False,False +QUICK,False,False +RANDOM,False,False +RANGE,False,False +RANK,False,False +READ,False,False +READS,False,False +READ_ONLY,False,False +READ_WRITE,False,False +REAL,False,False +REBUILD,False,False +RECOVER,False,False +RECURSIVE,False,False +REDOFILE,False,True +REDO_BUFFER_SIZE,False,False +REDUNDANT,False,False +REFERENCE,False,False +REFERENCES,False,False +REGEXP,False,False +REGISTRATION,False,False +RELAY,False,False +RELAYLOG,False,False +RELAY_LOG_FILE,False,False +RELAY_LOG_POS,False,False +RELAY_THREAD,False,False +RELEASE,False,False +RELOAD,False,False +REMOTE,False,True +REMOVE,False,False +RENAME,False,False +REORGANIZE,False,False +REPAIR,False,False +REPEAT,False,False +REPEATABLE,False,False +REPLACE,False,False +REPLICA,False,False +REPLICAS,False,False +REPLICATE_DO_DB,False,False +REPLICATE_DO_TABLE,False,False +REPLICATE_IGNORE_DB,False,False +REPLICATE_IGNORE_TABLE,False,False +REPLICATE_REWRITE_DB,False,False +REPLICATE_WILD_DO_TABLE,False,False +REPLICATE_WILD_IGNORE_TABLE,False,False +REPLICATION,False,False +REQUIRE,False,False +REQUIRE_ROW_FORMAT,False,False +RESET,False,False +RESIGNAL,False,False +RESOURCE,False,False +RESPECT,False,False +RESTART,False,False +RESTORE,False,False +RESTRICT,False,False +RESUME,False,False +RETAIN,False,False +RETURN,False,False +RETURNED_SQLSTATE,False,False +RETURNING,False,False +RETURNS,False,False +REUSE,False,False +REVERSE,False,False +REVOKE,False,False +RIGHT,False,False +RLIKE,False,False +ROLE,False,False +ROLLBACK,False,False +ROLLUP,False,False +ROTATE,False,False +ROUTINE,False,False +ROW,False,False +ROWS,False,False +ROW_COUNT,False,False +ROW_FORMAT,False,False +ROW_NUMBER,False,False +RTREE,False,False +SAVEPOINT,False,False +SCHEDULE,False,False +SCHEMA,False,False +SCHEMAS,False,False +SCHEMA_NAME,False,False +SECOND,False,False +SECONDARY,False,False +SECONDARY_ENGINE,False,False +SECONDARY_ENGINE_ATTRIBUTE,False,False +SECONDARY_LOAD,False,False +SECONDARY_UNLOAD,False,False +SECOND_MICROSECOND,False,False +SECURITY,False,False +SELECT,False,False +SENSITIVE,False,False +SEPARATOR,False,False +SERIAL,False,False +SERIALIZABLE,False,False +SERVER,False,False +SESSION,False,False +SET,False,False +SHARE,False,False +SHOW,False,False +SHUTDOWN,False,False +SIGNAL,False,False +SIGNED,False,False +SIMPLE,False,False +SKIP,False,False +SLAVE,False,False +SLOW,False,False +SMALLINT,False,False +SNAPSHOT,False,False +SOCKET,False,False +SOME,False,False +SONAME,False,False +SOUNDS,False,False +SOURCE,False,False +SOURCE_AUTO_POSITION,False,False +SOURCE_BIND,False,False +SOURCE_COMPRESSION_ALGORITHMS,False,False +SOURCE_CONNECT_RETRY,False,False +SOURCE_DELAY,False,False +SOURCE_HEARTBEAT_PERIOD,False,False +SOURCE_HOST,False,False +SOURCE_LOG_FILE,False,False +SOURCE_LOG_POS,False,False +SOURCE_PASSWORD,False,False +SOURCE_PORT,False,False +SOURCE_PUBLIC_KEY_PATH,False,False +SOURCE_RETRY_COUNT,False,False +SOURCE_SSL,False,False +SOURCE_SSL_CA,False,False +SOURCE_SSL_CAPATH,False,False +SOURCE_SSL_CERT,False,False +SOURCE_SSL_CIPHER,False,False +SOURCE_SSL_CRL,False,False +SOURCE_SSL_CRLPATH,False,False +SOURCE_SSL_KEY,False,False +SOURCE_SSL_VERIFY_SERVER_CERT,False,False +SOURCE_TLS_CIPHERSUITES,False,False +SOURCE_TLS_VERSION,False,False +SOURCE_USER,False,False +SOURCE_ZSTD_COMPRESSION_LEVEL,False,False +SPATIAL,False,False +SPECIFIC,False,False +SQL,False,False +SQLEXCEPTION,False,False +SQLSTATE,False,False +SQLWARNING,False,False +SQL_AFTER_GTIDS,False,False +SQL_AFTER_MTS_GAPS,False,False +SQL_BEFORE_GTIDS,False,False +SQL_BIG_RESULT,False,False +SQL_BUFFER_RESULT,False,False +SQL_CACHE,False,True +SQL_CALC_FOUND_ROWS,False,False +SQL_NO_CACHE,False,False +SQL_SMALL_RESULT,False,False +SQL_THREAD,False,False +SQL_TSI_DAY,False,False +SQL_TSI_HOUR,False,False +SQL_TSI_MINUTE,False,False +SQL_TSI_MONTH,False,False +SQL_TSI_QUARTER,False,False +SQL_TSI_SECOND,False,False +SQL_TSI_WEEK,False,False +SQL_TSI_YEAR,False,False +SRID,False,False +SSL,False,False +STACKED,False,False +START,False,False +STARTING,False,False +STARTS,False,False +STATS_AUTO_RECALC,False,False +STATS_PERSISTENT,False,False +STATS_SAMPLE_PAGES,False,False +STATUS,False,False +STOP,False,False +STORAGE,False,False +STORED,False,False +STRAIGHT_JOIN,False,False +STREAM,False,False +STRING,False,False +SUBCLASS_ORIGIN,False,False +SUBJECT,False,False +SUBPARTITION,False,False +SUBPARTITIONS,False,False +SUPER,False,False +SUSPEND,False,False +SWAPS,False,False +SWITCHES,False,False +SYSTEM,False,False +TABLE,False,False +TABLES,False,False +TABLESPACE,False,False +TABLE_CHECKSUM,False,False +TABLE_NAME,False,False +TEMPORARY,False,False +TEMPTABLE,False,False +TERMINATED,False,False +TEXT,False,False +THAN,False,False +THEN,False,False +THREAD_PRIORITY,False,False +TIES,False,False +TIME,False,False +TIMESTAMP,False,False +TIMESTAMPADD,False,False +TIMESTAMPDIFF,False,False +TINYBLOB,False,False +TINYINT,False,False +TINYTEXT,False,False +TLS,False,False +TO,False,False +TRAILING,False,False +TRANSACTION,False,False +TRIGGER,False,False +TRIGGERS,False,False +TRUE,False,False +TRUNCATE,False,False +TYPE,False,False +TYPES,False,False +UNBOUNDED,False,False +UNCOMMITTED,False,False +UNDEFINED,False,False +UNDO,False,False +UNDOFILE,False,False +UNDO_BUFFER_SIZE,False,False +UNICODE,False,False +UNINSTALL,False,False +UNION,False,False +UNIQUE,False,False +UNKNOWN,False,False +UNLOCK,False,False +UNREGISTER,False,False +UNSIGNED,False,False +UNTIL,False,False +UPDATE,False,False +UPGRADE,False,False +URL,False,False +USAGE,False,False +USE,False,False +USER,False,False +USER_RESOURCES,False,False +USE_FRM,False,False +USING,False,False +UTC_DATE,False,False +UTC_TIME,False,False +UTC_TIMESTAMP,False,False +VALIDATION,False,False +VALUE,False,False +VALUES,False,False +VARBINARY,False,False +VARCHAR,False,False +VARCHARACTER,False,False +VARIABLES,False,False +VARYING,False,False +VCPU,False,False +VIEW,False,False +VIRTUAL,False,False +VISIBLE,False,False +WAIT,False,False +WARNINGS,False,False +WEEK,False,False +WEIGHT_STRING,False,False +WHEN,False,False +WHERE,False,False +WHILE,False,False +WINDOW,False,False +WITH,False,False +WITHOUT,False,False +WORK,False,False +WRAPPER,False,False +WRITE,False,False +X509,False,False +XA,False,False +XID,False,False +XML,False,False +XOR,False,False +YEAR,False,False +YEAR_MONTH,False,False +ZEROFILL,False,False +ZONE,False,False +MySQL,False,False +The,False,False +A,False,False +ACTIVE,False,False +ADMIN,False,False +ARRAY,False,False +ATTRIBUTE,False,False +AUTHENTICATION,False,False +BUCKETS,False,False +BULK,False,False +CHALLENGE_RESPONSE,False,False +CLONE,False,False +COMPONENT,False,False +CUME_DIST,False,False +DEFINITION,False,False +DENSE_RANK,False,False +DESCRIPTION,False,False +EMPTY,False,False +ENFORCED,False,False +ENGINE_ATTRIBUTE,False,False +EXCEPT,False,False +EXCLUDE,False,False +FACTOR,False,False +FAILED_LOGIN_ATTEMPTS,False,False +FINISH,False,False +FIRST_VALUE,False,False +FOLLOWING,False,False +GENERATE,False,False +GEOMCOLLECTION,False,False +GET_MASTER_PUBLIC_KEY,False,False +GET_SOURCE_PUBLIC_KEY,False,False +GROUPING,False,False +GROUPS,False,False +GTID_ONLY,False,False +HISTOGRAM,False,False +HISTORY,False,False +INACTIVE,False,False +INITIAL,False,False +INITIATE,False,False +INTERSECT,False,False +INVISIBLE,False,False +JSON_TABLE,False,False +JSON_VALUE,False,False +KEYRING,False,False +LAG,False,False +LAST_VALUE,False,False +LATERAL,False,False +LEAD,False,False +LOCKED,False,False +MASTER_COMPRESSION_ALGORITHMS,False,False +MASTER_PUBLIC_KEY_PATH,False,False +MASTER_TLS_CIPHERSUITES,False,False +MASTER_ZSTD_COMPRESSION_LEVEL,False,False +MEMBER,False,False +NESTED,False,False +NETWORK_NAMESPACE,False,False +NOWAIT,False,False +NTH_VALUE,False,False +NTILE,False,False +NULLS,False,False +OF,False,False +OFF,False,False +OJ,False,False +OLD,False,False +OPTIONAL,False,False +ORDINALITY,False,False +ORGANIZATION,False,False +OTHERS,False,False +OVER,False,False +PASSWORD_LOCK_TIME,False,False +PATH,False,False +PERCENT_RANK,False,False +PERSIST,False,False +PERSIST_ONLY,False,False +PRECEDING,False,False +PRIVILEGE_CHECKS_USER,False,False +PROCESS,False,False +RANDOM,False,False +RANK,False,False +RECURSIVE,False,False +REFERENCE,False,False +REGISTRATION,False,False +REPLICA,False,False +REPLICAS,False,False +REQUIRE_ROW_FORMAT,False,False +RESOURCE,False,False +RESPECT,False,False +RESTART,False,False +RETAIN,False,False +RETURNING,False,False +REUSE,False,False +ROLE,False,False +ROW_NUMBER,False,False +SECONDARY,False,False +SECONDARY_ENGINE,False,False +SECONDARY_ENGINE_ATTRIBUTE,False,False +SECONDARY_LOAD,False,False +SECONDARY_UNLOAD,False,False +SKIP,False,False +SOURCE_AUTO_POSITION,False,False +SOURCE_BIND,False,False +SOURCE_COMPRESSION_ALGORITHMS,False,False +SOURCE_CONNECT_RETRY,False,False +SOURCE_DELAY,False,False +SOURCE_HEARTBEAT_PERIOD,False,False +SOURCE_HOST,False,False +SOURCE_LOG_FILE,False,False +SOURCE_LOG_POS,False,False +SOURCE_PASSWORD,False,False +SOURCE_PORT,False,False +SOURCE_PUBLIC_KEY_PATH,False,False +SOURCE_RETRY_COUNT,False,False +SOURCE_SSL,False,False +SOURCE_SSL_CA,False,False +SOURCE_SSL_CAPATH,False,False +SOURCE_SSL_CERT,False,False +SOURCE_SSL_CIPHER,False,False +SOURCE_SSL_CRL,False,False +SOURCE_SSL_CRLPATH,False,False +SOURCE_SSL_KEY,False,False +SOURCE_SSL_VERIFY_SERVER_CERT,False,False +SOURCE_TLS_CIPHERSUITES,False,False +SOURCE_TLS_VERSION,False,False +SOURCE_USER,False,False +SOURCE_ZSTD_COMPRESSION_LEVEL,False,False +SRID,False,False +STREAM,False,False +SYSTEM,False,False +THREAD_PRIORITY,False,False +TIES,False,False +TLS,False,False +UNBOUNDED,False,False +UNREGISTER,False,False +URL,False,False +VCPU,False,False +VISIBLE,False,False +WINDOW,False,False +ZONE,False,False \ No newline at end of file diff --git a/src/harlequin_mysql/py.typed b/src/harlequin_mysql/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..250537b --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from typing import Generator + +import pytest +from mysql.connector import connect + +from harlequin_mysql.adapter import ( + HarlequinMySQLAdapter, + HarlequinMySQLConnection, +) + + +@pytest.fixture +def connection() -> Generator[HarlequinMySQLConnection, None, None]: + mysqlconn = connect( + host="localhost", + user="root", + password="example", + database="mysql", + autocommit=True, + ) + cur = mysqlconn.cursor() + cur.execute("drop database if exists test;") + cur.execute("drop database if exists one;") + cur.execute("drop database if exists two;") + cur.execute("drop database if exists three;") + cur.execute("create database test;") + cur.close() + conn = HarlequinMySQLAdapter( + conn_str=tuple(), + host="localhost", + user="root", + password="example", + database="test", + ).connect() + yield conn + cur = mysqlconn.cursor() + cur.execute("drop database if exists test;") + cur.execute("drop database if exists one;") + cur.execute("drop database if exists two;") + cur.execute("drop database if exists three;") + cur.close() diff --git a/tests/test_adapter.py b/tests/test_adapter.py new file mode 100644 index 0000000..10fd1ae --- /dev/null +++ b/tests/test_adapter.py @@ -0,0 +1,220 @@ +from __future__ import annotations + +import sys + +import pytest +from harlequin import ( + HarlequinAdapter, + HarlequinCompletion, + HarlequinConnection, + HarlequinCursor, +) +from harlequin.catalog import Catalog, CatalogItem +from harlequin.exception import HarlequinConnectionError, HarlequinQueryError +from mysql.connector.cursor import MySQLCursor +from mysql.connector.pooling import PooledMySQLConnection +from textual_fastdatatable.backend import create_backend + +from harlequin_mysql.adapter import ( + HarlequinMySQLAdapter, + HarlequinMySQLConnection, +) + +if sys.version_info < (3, 10): + from importlib_metadata import entry_points +else: + from importlib.metadata import entry_points + + +def test_plugin_discovery() -> None: + PLUGIN_NAME = "mysql" + eps = entry_points(group="harlequin.adapter") + assert eps[PLUGIN_NAME] + adapter_cls = eps[PLUGIN_NAME].load() + assert issubclass(adapter_cls, HarlequinAdapter) + assert adapter_cls == HarlequinMySQLAdapter + + +def test_connect() -> None: + conn = HarlequinMySQLAdapter( + conn_str=tuple(), user="root", password="example" + ).connect() + assert isinstance(conn, HarlequinConnection) + + +def test_init_extra_kwargs() -> None: + assert HarlequinMySQLAdapter( + conn_str=tuple(), user="root", password="example", foo=1, bar="baz" + ).connect() + + +def test_connect_raises_connection_error() -> None: + with pytest.raises(HarlequinConnectionError): + _ = HarlequinMySQLAdapter(conn_str=("foo",)).connect() + + +@pytest.mark.parametrize( + "options,expected", + [ + ({}, "127.0.0.1:3306/"), + ({"host": "foo.bar"}, "foo.bar:3306/"), + ({"host": "foo.bar", "port": "3305"}, "foo.bar:3305/"), + ({"unix_socket": "/foo/bar"}, "/foo/bar:3306/"), + ({"unix_socket": "/foo/bar", "database": "baz"}, "/foo/bar:3306/baz"), + ], +) +def test_connection_id(options: dict[str, str | int | None], expected: str) -> None: + adapter = HarlequinMySQLAdapter( + conn_str=tuple(), + **options, # type: ignore[arg-type] + ) + assert adapter.connection_id == expected + + +def test_get_catalog(connection: HarlequinMySQLConnection) -> None: + catalog = connection.get_catalog() + assert isinstance(catalog, Catalog) + assert catalog.items + assert isinstance(catalog.items[0], CatalogItem) + assert any( + item.label == "test" and item.type_label == "db" for item in catalog.items + ) + + +def test_get_completions(connection: HarlequinMySQLConnection) -> None: + completions = connection.get_completions() + assert completions + assert isinstance(completions[0], HarlequinCompletion) + expected = ["action", "var_pop"] + filtered = list(filter(lambda x: x.label in expected, completions)) + assert len(filtered) == len(expected) + + +def test_execute_ddl(connection: HarlequinMySQLConnection) -> None: + cur = connection.execute("create table foo (a int)") + assert cur is None + + +def test_execute_select(connection: HarlequinMySQLConnection) -> None: + cur = connection.execute("select 1 as a") + assert isinstance(cur, HarlequinCursor) + assert cur.columns() == [("a", "##")] + data = cur.fetchall() + backend = create_backend(data) + assert backend.column_count == 1 + assert backend.row_count == 1 + + +def test_execute_select_no_records(connection: HarlequinMySQLConnection) -> None: + cur = connection.execute("select 1 as a where false") + assert isinstance(cur, HarlequinCursor) + assert cur.columns() == [("a", "##")] + data = cur.fetchall() + backend = create_backend(data) + assert backend.row_count == 0 + + +def test_execute_select_dupe_cols(connection: HarlequinMySQLConnection) -> None: + cur = connection.execute("select 1 as a, 2 as a, 3 as a") + assert isinstance(cur, HarlequinCursor) + assert len(cur.columns()) == 3 + data = cur.fetchall() + backend = create_backend(data) + assert backend.column_count == 3 + assert backend.row_count == 1 + + +def test_set_limit(connection: HarlequinMySQLConnection) -> None: + cur = connection.execute("select 1 as a union all select 2 union all select 3") + assert isinstance(cur, HarlequinCursor) + cur = cur.set_limit(2) + assert isinstance(cur, HarlequinCursor) + data = cur.fetchall() + backend = create_backend(data) + assert backend.column_count == 1 + assert backend.row_count == 2 + + +def test_execute_raises_query_error(connection: HarlequinMySQLConnection) -> None: + with pytest.raises(HarlequinQueryError): + _ = connection.execute("selec;") + + +def test_can_execute_pool_size_queries(connection: HarlequinMySQLConnection) -> None: + pool_size = connection._pool.pool_size + cursors: list[HarlequinCursor] = [] + for _ in range(pool_size): + cur = connection.execute("select 1") + assert cur is not None + cursors.append(cur) + assert len(cursors) == pool_size + + +def test_can_execute_pool_size_ddl(connection: HarlequinMySQLConnection) -> None: + pool_size = connection._pool.pool_size + cursors: list[None] = [] + for i in range(pool_size): + cur = connection.execute(f"create table t_{i} as select {i}") + assert cur is None + cursors.append(cur) + assert len(cursors) == pool_size + + +def test_execute_more_than_pool_size_queries_does_not_raise( + connection: HarlequinMySQLConnection, +) -> None: + pool_size = connection._pool.pool_size + cursors: list[HarlequinCursor] = [] + for _ in range(pool_size * 2): + cur = connection.execute("select 1") + if cur is not None: + cursors.append(cur) + assert len(cursors) == pool_size + + +def test_execute_more_than_pool_size_ddl_does_not_raise( + connection: HarlequinMySQLConnection, +) -> None: + pool_size = connection._pool.pool_size + number_of_ddl_queries = pool_size * 2 + cursors: list[None] = [] + for i in range(number_of_ddl_queries): + cur = connection.execute(f"create table t_{i} as select {i}") + assert cur is None + cursors.append(cur) + assert len(cursors) == number_of_ddl_queries + + +def test_use_database_updates_pool(connection: HarlequinMySQLConnection) -> None: + conn, cur = connection.safe_get_mysql_cursor() + assert conn is not None + assert cur is not None + assert conn.database == "test" + cur.close() + conn.close() + + connection.execute("use mysql") + + pool_size = connection._pool.pool_size + + conns: list[PooledMySQLConnection] = [] + curs: list[MySQLCursor] = [] + for _ in range(pool_size): + conn, cur = connection.safe_get_mysql_cursor() + assert conn is not None + assert cur is not None + assert conn.database == "mysql" + conns.append(conn) + curs.append(cur) + + assert len(conns) == pool_size + for cur in curs: + cur.close() + for conn in conns: + conn.close() + + +def test_close(connection: HarlequinMySQLConnection) -> None: + connection.close() + # run again to test error handling. + connection.close() diff --git a/tests/test_catalog.py b/tests/test_catalog.py new file mode 100644 index 0000000..2ea57e0 --- /dev/null +++ b/tests/test_catalog.py @@ -0,0 +1,85 @@ +import pytest + +from harlequin_mysql.adapter import HarlequinMySQLConnection +from harlequin_mysql.catalog import ( + ColumnCatalogItem, + DatabaseCatalogItem, + RelationCatalogItem, + TableCatalogItem, + ViewCatalogItem, +) + + +@pytest.fixture +def connection_with_objects( + connection: HarlequinMySQLConnection, +) -> HarlequinMySQLConnection: + connection.execute("create database one") + connection.execute("create table one.foo as select 1 as a, '2' as b") + connection.execute("create table one.bar as select 1 as a, '2' as b") + connection.execute("create table one.baz as select 1 as a, '2' as b") + connection.execute("create database two") + connection.execute("create view two.qux as select * from one.foo") + connection.execute("create database three") + # the original connection fixture will clean this up. + return connection + + +def test_catalog(connection_with_objects: HarlequinMySQLConnection) -> None: + conn = connection_with_objects + + catalog = conn.get_catalog() + + # five databases: dev, test, one, two, and three. + assert len(catalog.items) == 5 + + database_items = catalog.items + assert all(isinstance(item, DatabaseCatalogItem) for item in database_items) + + [database_one_item] = filter(lambda item: item.label == "one", database_items) + assert isinstance(database_one_item, DatabaseCatalogItem) + assert not database_one_item.children + assert not database_one_item.loaded + + table_items = database_one_item.fetch_children() + assert all(isinstance(item, RelationCatalogItem) for item in table_items) + + [foo_item] = filter(lambda item: item.label == "foo", table_items) + assert isinstance(foo_item, TableCatalogItem) + assert not foo_item.children + assert not foo_item.loaded + + foo_column_items = foo_item.fetch_children() + assert all(isinstance(item, ColumnCatalogItem) for item in foo_column_items) + + [database_two_item] = filter(lambda item: item.label == "two", database_items) + assert isinstance(database_two_item, DatabaseCatalogItem) + assert not database_two_item.children + assert not database_two_item.loaded + + view_items = database_two_item.fetch_children() + assert all(isinstance(item, ViewCatalogItem) for item in view_items) + + [qux_item] = filter(lambda item: item.label == "qux", view_items) + assert isinstance(qux_item, ViewCatalogItem) + assert not qux_item.children + assert not qux_item.loaded + + qux_column_items = qux_item.fetch_children() + assert all(isinstance(item, ColumnCatalogItem) for item in qux_column_items) + + assert [item.label for item in foo_column_items] == [ + item.label for item in qux_column_items + ] + + # ensure calling fetch_children on cols doesn't raise + children_items = foo_column_items[0].fetch_children() + assert not children_items + + [database_three_item] = filter(lambda item: item.label == "three", database_items) + assert isinstance(database_three_item, DatabaseCatalogItem) + assert not database_three_item.children + assert not database_three_item.loaded + + three_children = database_three_item.fetch_children() + assert not three_children