diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..f2752b8 --- /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 harlequin-trino 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.HARLEQUIN_TRINO_PYPI_TOKEN }} + - name: Get harlequin-trino Version + id: harlequin_trino_version + run: echo "harlequin_trino_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.harlequin_trino_version.outputs.harlequin_trino_version }} + target_commitish: main + token: ${{ secrets.HARLEQUIN_TRINO_RELEASE_TOKEN }} + body_path: CHANGELOG.md + files: | + LICENSE + dist/*harlequin*.whl + dist/*harlequin*.tar.gz \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9bccdd1 --- /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 harlequin-trino 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. \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2e85809 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Harlequin-Trino CHANGELOG + +All notable changes to this project will be documented in this file. + +## [Unreleased] + +### Features +- Adds a basic Trino adapter with most common connection options. + diff --git a/LICENSE b/LICENSE index 04ec0c8..44fc400 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Ted Conbeer +Copyright (c) 2023 Tyler Hillery Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..044500c --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +.PHONY: check +check: + ruff format . + ruff . --fix + mypy + pytest + +.PHONY: init +init: + docker-compose up -d + +.PHONY: clean +clean: + docker-compose down + +.PHONY: serve +serve: + harlequin -P None -a trino --host localhost -p 8080 -U trino \ No newline at end of file diff --git a/README.md b/README.md index 09863fb..d4464a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,72 @@ -# harlequin-adapter-template -This repo provides a template you can use to accelerate development of a new [Harlequin](https://harlequin.sh) database adapter. +# harlequin-trino -For an in-depth guide on writing your own adapter, see the [Harlequin Docs](https://harlequin.sh/docs/contributing/adapter-guide). \ No newline at end of file +This repo provides the Harlequin adapter for Trino. + +## Installation + +`harlequin-trino` 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-trino +``` + +### Using poetry + +```bash +poetry add harlequin-trino +``` + +### Using pipx + +If you do not already have Harlequin installed: + +```bash +pip install harlequin-trino +``` + +If you would like to add the Trino adapter to an existing Harlequin installation: + +```bash +pipx inject harlequin harlequin-trino +``` + +### As an Extra +Alternatively, you can install Harlequin with the `trino` extra: + +```bash +pip install harlequin[trino] +``` + +```bash +poetry add harlequin[trino] +``` + +```bash +pipx install harlequin[trino] +``` + +## Usage and Configuration +For a minimum connection you are going to need: +- host +- port +- user + +```bash +harlequin -a trino -h localhost -p 8080 -U my_user +``` + +If your trino instance requires a password you can set the `--require_auth` flag to password and use the `--password` flag for your password +```bash +harlequin -a trino -h localhost -p 8080 -U my_user --password my-pass --require_auth password +``` + +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/trino/index). \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c5bdda8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3.1' + +services: + db: + image: postgres:latest + restart: always + environment: + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + + trino: + image: trinodb/trino + restart: always + ports: + - 8080:8080 + volumes: + - ./trino/etc:/etc/trino + + adminer: + image: adminer + restart: always + ports: + - 8081:8080 + +networks: + shared_network: + driver: bridge diff --git a/poetry.lock b/poetry.lock index a97a8c8..76f8c30 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,43 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +optional = false +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] [[package]] name = "cfgv" @@ -11,6 +50,105 @@ files = [ {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + [[package]] name = "click" version = "8.1.7" @@ -127,13 +265,13 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "harlequin" -version = "1.7.0" +version = "1.8.0" description = "The SQL IDE for Your Terminal." optional = false python-versions = ">=3.8.1,<4.0.0" files = [ - {file = "harlequin-1.7.0-py3-none-any.whl", hash = "sha256:18d364c3b3ff55bb2ff62fabc4267b104e63d4a2c4742491030c0338f1ccdb18"}, - {file = "harlequin-1.7.0.tar.gz", hash = "sha256:ee56e3c7b190ef075061a91de7f13b474e490bdded4f5e3f0123f6f0024943d5"}, + {file = "harlequin-1.8.0-py3-none-any.whl", hash = "sha256:ec475bfeab210c222bd597625c136bbe19ce9348243787b3444ed69aa25c3ecb"}, + {file = "harlequin-1.8.0.tar.gz", hash = "sha256:38a0ed1ed47bb6cf13c7fbed9f9e59d6ee644a069db4ef5f8381d90441f03595"}, ] [package.dependencies] @@ -145,14 +283,16 @@ pyperclip = ">=1.8.2,<2.0.0" questionary = ">=2.0.1,<3.0.0" rich-click = ">=1.7.1,<2.0.0" shandy-sqlfmt = ">=0.19.0" -textual = "0.41.0" -textual-fastdatatable = "0.4.0" -textual-textarea = "0.9.2" +textual = "0.46.0" +textual-fastdatatable = "0.5.0" +textual-textarea = "0.9.5" tomli = {version = ">=2.0.1,<3.0.0", markers = "python_full_version < \"3.11.0\""} tomlkit = ">=0.12.3,<0.13.0" [package.extras] -postgres = ["harlequin-postgres (>=0.1,<0.2)"] +bigquery = ["harlequin-bigquery (>=1.0,<2.0)"] +mysql = ["harlequin-mysql (>=0.1,<0.2)"] +postgres = ["harlequin-postgres (>=0.2,<0.3)"] [[package]] name = "identify" @@ -168,15 +308,26 @@ files = [ [package.extras] license = ["ukkonen"] +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] @@ -362,38 +513,38 @@ files = [ [[package]] name = "mypy" -version = "1.7.1" +version = "1.8.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, - {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, - {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, - {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, - {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, - {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, - {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, - {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, - {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, - {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, - {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, - {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, - {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, - {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, - {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, - {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, - {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, - {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, - {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, ] [package.dependencies] @@ -544,47 +695,47 @@ wcwidth = "*" [[package]] name = "pyarrow" -version = "14.0.1" +version = "14.0.2" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-14.0.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:96d64e5ba7dceb519a955e5eeb5c9adcfd63f73a56aea4722e2cc81364fc567a"}, - {file = "pyarrow-14.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a8ae88c0038d1bc362a682320112ee6774f006134cd5afc291591ee4bc06505"}, - {file = "pyarrow-14.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f6f053cb66dc24091f5511e5920e45c83107f954a21032feadc7b9e3a8e7851"}, - {file = "pyarrow-14.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:906b0dc25f2be12e95975722f1e60e162437023f490dbd80d0deb7375baf3171"}, - {file = "pyarrow-14.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:78d4a77a46a7de9388b653af1c4ce539350726cd9af62e0831e4f2bd0c95a2f4"}, - {file = "pyarrow-14.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:06ca79080ef89d6529bb8e5074d4b4f6086143b2520494fcb7cf8a99079cde93"}, - {file = "pyarrow-14.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:32542164d905002c42dff896efdac79b3bdd7291b1b74aa292fac8450d0e4dcd"}, - {file = "pyarrow-14.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:c7331b4ed3401b7ee56f22c980608cf273f0380f77d0f73dd3c185f78f5a6220"}, - {file = "pyarrow-14.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:922e8b49b88da8633d6cac0e1b5a690311b6758d6f5d7c2be71acb0f1e14cd61"}, - {file = "pyarrow-14.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58c889851ca33f992ea916b48b8540735055201b177cb0dcf0596a495a667b00"}, - {file = "pyarrow-14.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30d8494870d9916bb53b2a4384948491444741cb9a38253c590e21f836b01222"}, - {file = "pyarrow-14.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:be28e1a07f20391bb0b15ea03dcac3aade29fc773c5eb4bee2838e9b2cdde0cb"}, - {file = "pyarrow-14.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:981670b4ce0110d8dcb3246410a4aabf5714db5d8ea63b15686bce1c914b1f83"}, - {file = "pyarrow-14.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:4756a2b373a28f6166c42711240643fb8bd6322467e9aacabd26b488fa41ec23"}, - {file = "pyarrow-14.0.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:cf87e2cec65dd5cf1aa4aba918d523ef56ef95597b545bbaad01e6433851aa10"}, - {file = "pyarrow-14.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:470ae0194fbfdfbf4a6b65b4f9e0f6e1fa0ea5b90c1ee6b65b38aecee53508c8"}, - {file = "pyarrow-14.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6263cffd0c3721c1e348062997babdf0151301f7353010c9c9a8ed47448f82ab"}, - {file = "pyarrow-14.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8089d7e77d1455d529dbd7cff08898bbb2666ee48bc4085203af1d826a33cc"}, - {file = "pyarrow-14.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fada8396bc739d958d0b81d291cfd201126ed5e7913cb73de6bc606befc30226"}, - {file = "pyarrow-14.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:2a145dab9ed7849fc1101bf03bcdc69913547f10513fdf70fc3ab6c0a50c7eee"}, - {file = "pyarrow-14.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:05fe7994745b634c5fb16ce5717e39a1ac1fac3e2b0795232841660aa76647cd"}, - {file = "pyarrow-14.0.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a8eeef015ae69d104c4c3117a6011e7e3ecd1abec79dc87fd2fac6e442f666ee"}, - {file = "pyarrow-14.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3c76807540989fe8fcd02285dd15e4f2a3da0b09d27781abec3adc265ddbeba1"}, - {file = "pyarrow-14.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:450e4605e3c20e558485f9161a79280a61c55efe585d51513c014de9ae8d393f"}, - {file = "pyarrow-14.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:323cbe60210173ffd7db78bfd50b80bdd792c4c9daca8843ef3cd70b186649db"}, - {file = "pyarrow-14.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0140c7e2b740e08c5a459439d87acd26b747fc408bde0a8806096ee0baaa0c15"}, - {file = "pyarrow-14.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:e592e482edd9f1ab32f18cd6a716c45b2c0f2403dc2af782f4e9674952e6dd27"}, - {file = "pyarrow-14.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d264ad13605b61959f2ae7c1d25b1a5b8505b112715c961418c8396433f213ad"}, - {file = "pyarrow-14.0.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01e44de9749cddc486169cb632f3c99962318e9dacac7778315a110f4bf8a450"}, - {file = "pyarrow-14.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0351fecf0e26e152542bc164c22ea2a8e8c682726fce160ce4d459ea802d69c"}, - {file = "pyarrow-14.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33c1f6110c386464fd2e5e4ea3624466055bbe681ff185fd6c9daa98f30a3f9a"}, - {file = "pyarrow-14.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11e045dfa09855b6d3e7705a37c42e2dc2c71d608fab34d3c23df2e02df9aec3"}, - {file = "pyarrow-14.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:097828b55321897db0e1dbfc606e3ff8101ae5725673498cbfa7754ee0da80e4"}, - {file = "pyarrow-14.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1daab52050a1c48506c029e6fa0944a7b2436334d7e44221c16f6f1b2cc9c510"}, - {file = "pyarrow-14.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:3f6d5faf4f1b0d5a7f97be987cf9e9f8cd39902611e818fe134588ee99bf0283"}, - {file = "pyarrow-14.0.1.tar.gz", hash = "sha256:b8b3f4fe8d4ec15e1ef9b599b94683c5216adaed78d5cb4c606180546d1e2ee1"}, + {file = "pyarrow-14.0.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:ba9fe808596c5dbd08b3aeffe901e5f81095baaa28e7d5118e01354c64f22807"}, + {file = "pyarrow-14.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:22a768987a16bb46220cef490c56c671993fbee8fd0475febac0b3e16b00a10e"}, + {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dbba05e98f247f17e64303eb876f4a80fcd32f73c7e9ad975a83834d81f3fda"}, + {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a898d134d00b1eca04998e9d286e19653f9d0fcb99587310cd10270907452a6b"}, + {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:87e879323f256cb04267bb365add7208f302df942eb943c93a9dfeb8f44840b1"}, + {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:76fc257559404ea5f1306ea9a3ff0541bf996ff3f7b9209fc517b5e83811fa8e"}, + {file = "pyarrow-14.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0c4a18e00f3a32398a7f31da47fefcd7a927545b396e1f15d0c85c2f2c778cd"}, + {file = "pyarrow-14.0.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:87482af32e5a0c0cce2d12eb3c039dd1d853bd905b04f3f953f147c7a196915b"}, + {file = "pyarrow-14.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:059bd8f12a70519e46cd64e1ba40e97eae55e0cbe1695edd95384653d7626b23"}, + {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f16111f9ab27e60b391c5f6d197510e3ad6654e73857b4e394861fc79c37200"}, + {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06ff1264fe4448e8d02073f5ce45a9f934c0f3db0a04460d0b01ff28befc3696"}, + {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6dd4f4b472ccf4042f1eab77e6c8bce574543f54d2135c7e396f413046397d5a"}, + {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:32356bfb58b36059773f49e4e214996888eeea3a08893e7dbde44753799b2a02"}, + {file = "pyarrow-14.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:52809ee69d4dbf2241c0e4366d949ba035cbcf48409bf404f071f624ed313a2b"}, + {file = "pyarrow-14.0.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:c87824a5ac52be210d32906c715f4ed7053d0180c1060ae3ff9b7e560f53f944"}, + {file = "pyarrow-14.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a25eb2421a58e861f6ca91f43339d215476f4fe159eca603c55950c14f378cc5"}, + {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c1da70d668af5620b8ba0a23f229030a4cd6c5f24a616a146f30d2386fec422"}, + {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cc61593c8e66194c7cdfae594503e91b926a228fba40b5cf25cc593563bcd07"}, + {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:78ea56f62fb7c0ae8ecb9afdd7893e3a7dbeb0b04106f5c08dbb23f9c0157591"}, + {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:37c233ddbce0c67a76c0985612fef27c0c92aef9413cf5aa56952f359fcb7379"}, + {file = "pyarrow-14.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:e4b123ad0f6add92de898214d404e488167b87b5dd86e9a434126bc2b7a5578d"}, + {file = "pyarrow-14.0.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:e354fba8490de258be7687f341bc04aba181fc8aa1f71e4584f9890d9cb2dec2"}, + {file = "pyarrow-14.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20e003a23a13da963f43e2b432483fdd8c38dc8882cd145f09f21792e1cf22a1"}, + {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc0de7575e841f1595ac07e5bc631084fd06ca8b03c0f2ecece733d23cd5102a"}, + {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e986dc859712acb0bd45601229021f3ffcdfc49044b64c6d071aaf4fa49e98"}, + {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:f7d029f20ef56673a9730766023459ece397a05001f4e4d13805111d7c2108c0"}, + {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:209bac546942b0d8edc8debda248364f7f668e4aad4741bae58e67d40e5fcf75"}, + {file = "pyarrow-14.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:1e6987c5274fb87d66bb36816afb6f65707546b3c45c44c28e3c4133c010a881"}, + {file = "pyarrow-14.0.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a01d0052d2a294a5f56cc1862933014e696aa08cc7b620e8c0cce5a5d362e976"}, + {file = "pyarrow-14.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a51fee3a7db4d37f8cda3ea96f32530620d43b0489d169b285d774da48ca9785"}, + {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64df2bf1ef2ef14cee531e2dfe03dd924017650ffaa6f9513d7a1bb291e59c15"}, + {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c0fa3bfdb0305ffe09810f9d3e2e50a2787e3a07063001dcd7adae0cee3601a"}, + {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c65bf4fd06584f058420238bc47a316e80dda01ec0dfb3044594128a6c2db794"}, + {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:63ac901baec9369d6aae1cbe6cca11178fb018a8d45068aaf5bb54f94804a866"}, + {file = "pyarrow-14.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:75ee0efe7a87a687ae303d63037d08a48ef9ea0127064df18267252cfe2e9541"}, + {file = "pyarrow-14.0.2.tar.gz", hash = "sha256:36cef6ba12b499d864d1def3e990f97949e0b79400d08b7cf74504ffbd3eb025"}, ] [package.dependencies] @@ -637,6 +788,31 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2023.3.post1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -710,6 +886,27 @@ files = [ [package.dependencies] prompt_toolkit = ">=2.0,<=3.0.36" +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + [[package]] name = "rich" version = "13.7.0" @@ -750,39 +947,39 @@ dev = ["flake8", "flake8-docstrings", "mypy", "packaging", "pre-commit", "pytest [[package]] name = "ruff" -version = "0.1.8" +version = "0.1.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.8-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7de792582f6e490ae6aef36a58d85df9f7a0cfd1b0d4fe6b4fb51803a3ac96fa"}, - {file = "ruff-0.1.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c8e3255afd186c142eef4ec400d7826134f028a85da2146102a1172ecc7c3696"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff78a7583020da124dd0deb835ece1d87bb91762d40c514ee9b67a087940528b"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd8ee69b02e7bdefe1e5da2d5b6eaaddcf4f90859f00281b2333c0e3a0cc9cd6"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05b0ddd7ea25495e4115a43125e8a7ebed0aa043c3d432de7e7d6e8e8cd6448"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e6f08ca730f4dc1b76b473bdf30b1b37d42da379202a059eae54ec7fc1fbcfed"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f35960b02df6b827c1b903091bb14f4b003f6cf102705efc4ce78132a0aa5af3"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d076717c67b34c162da7c1a5bda16ffc205e0e0072c03745275e7eab888719f"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a21ab023124eafb7cef6d038f835cb1155cd5ea798edd8d9eb2f8b84be07d9"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ce697c463458555027dfb194cb96d26608abab920fa85213deb5edf26e026664"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db6cedd9ffed55548ab313ad718bc34582d394e27a7875b4b952c2d29c001b26"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:05ffe9dbd278965271252704eddb97b4384bf58b971054d517decfbf8c523f05"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5daaeaf00ae3c1efec9742ff294b06c3a2a9db8d3db51ee4851c12ad385cda30"}, - {file = "ruff-0.1.8-py3-none-win32.whl", hash = "sha256:e49fbdfe257fa41e5c9e13c79b9e79a23a79bd0e40b9314bc53840f520c2c0b3"}, - {file = "ruff-0.1.8-py3-none-win_amd64.whl", hash = "sha256:f41f692f1691ad87f51708b823af4bb2c5c87c9248ddd3191c8f088e66ce590a"}, - {file = "ruff-0.1.8-py3-none-win_arm64.whl", hash = "sha256:aa8ee4f8440023b0a6c3707f76cadce8657553655dcbb5fc9b2f9bb9bee389f6"}, - {file = "ruff-0.1.8.tar.gz", hash = "sha256:f7ee467677467526cfe135eab86a40a0e8db43117936ac4f9b469ce9cdb3fb62"}, + {file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e6a212f436122ac73df851f0cf006e0c6612fe6f9c864ed17ebefce0eff6a5fd"}, + {file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:28d920e319783d5303333630dae46ecc80b7ba294aeffedf946a02ac0b7cc3db"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104aa9b5e12cb755d9dce698ab1b97726b83012487af415a4512fedd38b1459e"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e63bf5a4a91971082a4768a0aba9383c12392d0d6f1e2be2248c1f9054a20da"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d0738917c203246f3e275b37006faa3aa96c828b284ebfe3e99a8cb413c8c4b"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69dac82d63a50df2ab0906d97a01549f814b16bc806deeac4f064ff95c47ddf5"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2aec598fb65084e41a9c5d4b95726173768a62055aafb07b4eff976bac72a592"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:744dfe4b35470fa3820d5fe45758aace6269c578f7ddc43d447868cfe5078bcb"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479ca4250cab30f9218b2e563adc362bd6ae6343df7c7b5a7865300a5156d5a6"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:aa8344310f1ae79af9ccd6e4b32749e93cddc078f9b5ccd0e45bd76a6d2e8bb6"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:837c739729394df98f342319f5136f33c65286b28b6b70a87c28f59354ec939b"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e6837202c2859b9f22e43cb01992373c2dbfeae5c0c91ad691a4a2e725392464"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:331aae2cd4a0554667ac683243b151c74bd60e78fb08c3c2a4ac05ee1e606a39"}, + {file = "ruff-0.1.9-py3-none-win32.whl", hash = "sha256:8151425a60878e66f23ad47da39265fc2fad42aed06fb0a01130e967a7a064f4"}, + {file = "ruff-0.1.9-py3-none-win_amd64.whl", hash = "sha256:c497d769164df522fdaf54c6eba93f397342fe4ca2123a2e014a5b8fc7df81c7"}, + {file = "ruff-0.1.9-py3-none-win_arm64.whl", hash = "sha256:0e17f53bcbb4fff8292dfd84cf72d767b5e146f009cccd40c2fad27641f8a7a9"}, + {file = "ruff-0.1.9.tar.gz", hash = "sha256:b041dee2734719ddbb4518f762c982f2e912e7f28b8ee4fe1dee0b15d1b6e800"}, ] [[package]] name = "setuptools" -version = "69.0.2" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] @@ -792,19 +989,19 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar [[package]] name = "shandy-sqlfmt" -version = "0.21.0" +version = "0.21.1" description = "sqlfmt formats your dbt SQL files so you don't have to." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "shandy_sqlfmt-0.21.0-py3-none-any.whl", hash = "sha256:7c7cd00470cd0631f05c0fdb83e218f9d2d4391df9deb0f6eb450bc98ced56c6"}, - {file = "shandy_sqlfmt-0.21.0.tar.gz", hash = "sha256:af5d7bd503668c05489da118ff97a65a396fafeb534040808e672a3a7e1757ea"}, + {file = "shandy_sqlfmt-0.21.1-py3-none-any.whl", hash = "sha256:cc1b315d5c5c26e3a67d2aa9ea201bf3204d342dc0a4b33bf449ad67dfb00e64"}, + {file = "shandy_sqlfmt-0.21.1.tar.gz", hash = "sha256:7070712d0f7bc033e6150f8127e13107e02685c3f2015ea21cf4bcc7ef26b78a"}, ] [package.dependencies] click = ">=8.0,<9.0" jinja2 = ">=3.0,<4.0" -platformdirs = ">=2.4,<4.0" +platformdirs = ">=2.4,<5.0" tomli = {version = ">=2.0,<3.0", markers = "python_version < \"3.11\""} tqdm = ">=4.0,<5.0" @@ -812,19 +1009,29 @@ tqdm = ">=4.0,<5.0" jinjafmt = ["black"] sqlfmt-primer = ["gitpython (>=3.1.24,<4.0.0)"] +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + [[package]] name = "textual" -version = "0.41.0" +version = "0.46.0" description = "Modern Text User Interface framework" optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.8,<4.0" files = [ - {file = "textual-0.41.0-py3-none-any.whl", hash = "sha256:ebf5f04a96721adb8685aae32a98d4a4098dafbfef59b1fb43ca7ac2c1ed5049"}, - {file = "textual-0.41.0.tar.gz", hash = "sha256:73fb675a90ddded17d59ebd864dedaf82a3e7377e68ba1601581281dfd47ea86"}, + {file = "textual-0.46.0-py3-none-any.whl", hash = "sha256:3f8f3769860726d9eb653b164e7a3b8cbd17ea8d625c260a9a6dd3dafece81eb"}, + {file = "textual-0.46.0.tar.gz", hash = "sha256:66d30f07d082ee5083ea898103e70b8720a98658e0bd3153fbb934a437ffe6f5"}, ] [package.dependencies] -importlib-metadata = ">=4.11.3" markdown-it-py = {version = ">=2.1.0", extras = ["linkify", "plugins"]} rich = ">=13.3.3" tree-sitter = {version = ">=0.20.1,<0.21.0", optional = true, markers = "extra == \"syntax\""} @@ -836,13 +1043,13 @@ syntax = ["tree-sitter (>=0.20.1,<0.21.0)", "tree_sitter_languages (>=1.7.0)"] [[package]] name = "textual-fastdatatable" -version = "0.4.0" +version = "0.5.0" description = "A performance-focused reimplementation of Textual's DataTable widget, with a pluggable data storage backend." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "textual_fastdatatable-0.4.0-py3-none-any.whl", hash = "sha256:8c2c1f31366bfd4214eec1fb64942a2c8009e6ffb174cb75685d68b4c31bf627"}, - {file = "textual_fastdatatable-0.4.0.tar.gz", hash = "sha256:7259a4a9c2830441f627e6bf8a1de22198cc1eb209fac11132be5043062abaaf"}, + {file = "textual_fastdatatable-0.5.0-py3-none-any.whl", hash = "sha256:1541e2fbc2f4a50f9e29b3a0b8b0487df850c898a03f50c8b0f97e25af4555f3"}, + {file = "textual_fastdatatable-0.5.0.tar.gz", hash = "sha256:b80ec43b53081204f21889200b0306c470d2d3210d91676cf0859f152a9df19f"}, ] [package.dependencies] @@ -851,13 +1058,13 @@ textual = ">=0.41.0" [[package]] name = "textual-textarea" -version = "0.9.2" +version = "0.9.5" description = "A text area (multi-line input) with syntax highlighting for Textual" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "textual_textarea-0.9.2-py3-none-any.whl", hash = "sha256:e71215b5b15f49fab6ac9d288a433c27eb2150309634d18ebf0c3228b29a90bf"}, - {file = "textual_textarea-0.9.2.tar.gz", hash = "sha256:1c53fb73467ca630e965726524aa4604e6dc5f5966104e7f8f8fd3be963c4bff"}, + {file = "textual_textarea-0.9.5-py3-none-any.whl", hash = "sha256:3193944d094e6e0bb5d751b14a330b17620bedd36fcc487ee6f6af812b084182"}, + {file = "textual_textarea-0.9.5.tar.gz", hash = "sha256:4869ed28ba01bb557391227eb844f57ff40523c8f3343863c892a916dbb769b9"}, ] [package.dependencies] @@ -1064,6 +1271,31 @@ files = [ [package.dependencies] tree-sitter = "*" +[[package]] +name = "trino" +version = "0.327.0" +description = "Client for the Trino distributed SQL Engine" +optional = false +python-versions = ">=3.7" +files = [ + {file = "trino-0.327.0-py3-none-any.whl", hash = "sha256:56d253a814bd5da545cc68e1bc8c28c0b80f07df6411aa0424197c025c78998e"}, + {file = "trino-0.327.0.tar.gz", hash = "sha256:07370044158cb95f6f6b03720a1afb8980b75092a59025fe602af9858c2fd4a0"}, +] + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +python-dateutil = "*" +pytz = "*" +requests = ">=2.31.0" +tzlocal = "*" + +[package.extras] +all = ["requests-kerberos", "sqlalchemy (>=1.3)"] +external-authentication-token-cache = ["keyring"] +kerberos = ["requests-kerberos"] +sqlalchemy = ["sqlalchemy (>=1.3)"] +tests = ["black", "httpretty (<1.1)", "isort", "pre-commit", "pytest", "pytest-runner", "requests-kerberos", "sqlalchemy (>=1.3)"] + [[package]] name = "typing-extensions" version = "4.9.0" @@ -1075,6 +1307,35 @@ files = [ {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "tzlocal" +version = "5.2" +description = "tzinfo object for the local timezone" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, + {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, +] + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "uc-micro-py" version = "1.0.2" @@ -1089,6 +1350,22 @@ files = [ [package.extras] test = ["coverage", "pytest", "pytest-cov"] +[[package]] +name = "urllib3" +version = "2.1.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + [[package]] name = "virtualenv" version = "20.25.0" @@ -1138,4 +1415,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "35b7e4a8834dd4fc7c9eed8f2694b2be430877f7ef0460161e4c9fdb3331a704" +content-hash = "408f18e89e6dc1f5ff00ca080c4f50badf4aa59deac15313ce96f50eca6c93fc" diff --git a/pyproject.toml b/pyproject.toml index 37a6b0c..3ff5ba4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,20 +1,21 @@ [tool.poetry] -name = "harlequin_myadapter" +name = "harlequin_trino" version = "0.1.0" -description = "A Harlequin adapter for ." -authors = ["Ted Conbeer "] +description = "A Harlequin adapter for Trino." +authors = ["Tyler Hillery "] license = "MIT" readme = "README.md" packages = [ - { include = "harlequin_myadapter", from = "src" }, + { include = "harlequin_trino", from = "src" }, ] [tool.poetry.plugins."harlequin.adapter"] -my-adapter = "harlequin_myadapter:MyAdapter" +trino = "harlequin_trino:HarlequinTrinoAdapter" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" harlequin = "^1.7" +trino = "^0.327.0" [tool.poetry.group.dev.dependencies] ruff = "^0.1.6" @@ -62,3 +63,7 @@ warn_unused_configs = true no_implicit_reexport = true strict_equality = true + +[[tool.mypy.overrides]] +module = ["trino.dbapi", "trino.auth"] +ignore_missing_imports = true \ No newline at end of file diff --git a/src/harlequin_myadapter/__init__.py b/src/harlequin_myadapter/__init__.py deleted file mode 100644 index ff8486a..0000000 --- a/src/harlequin_myadapter/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from harlequin_myadapter.adapter import MyAdapter - -__all__ = ["MyAdapter"] diff --git a/src/harlequin_myadapter/adapter.py b/src/harlequin_myadapter/adapter.py deleted file mode 100644 index cad7ee3..0000000 --- a/src/harlequin_myadapter/adapter.py +++ /dev/null @@ -1,139 +0,0 @@ -from __future__ import annotations - -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 HarlequinConnectionError, HarlequinQueryError -from textual_fastdatatable.backend import AutoBackendType - -from harlequin_myadapter.cli_options import MYADAPTER_OPTIONS - - -class MyCursor(HarlequinCursor): - def __init__(self, *args: Any, **kwargs: Any) -> None: - self.cur = args[0] - self._limit: int | None = None - - def columns(self) -> list[tuple[str, str]]: - names = self.cur.column_names - types = self.cur.column_types - return list(zip(names, types)) - - def set_limit(self, limit: int) -> MyCursor: - self._limit = limit - return self - - def fetchall(self) -> AutoBackendType: - try: - if self._limit is None: - return self.cur.fetchall() - else: - return self.cur.fetchmany(self._limit) - except Exception as e: - raise HarlequinQueryError( - msg=str(e), - title="Harlequin encountered an error while executing your query.", - ) from e - - -class MyConnection(HarlequinConnection): - def __init__( - self, conn_str: Sequence[str], *args: Any, init_message: str = "", **kwargs: Any - ) -> None: - self.init_message = init_message - try: - self.conn = "your database library's connect method goes here" - except Exception as e: - raise HarlequinConnectionError( - msg=str(e), title="Harlequin could not connect to your database." - ) from e - - def execute(self, query: str) -> HarlequinCursor | None: - try: - cur = self.conn.execute(query) # type: ignore - except Exception as e: - raise HarlequinQueryError( - msg=str(e), - title="Harlequin encountered an error while executing your query.", - ) from e - else: - if cur is not None: - return MyCursor(cur) - else: - return None - - def get_catalog(self) -> Catalog: - databases = self.conn.list_databases() - db_items: list[CatalogItem] = [] - for db in databases: - schemas = self.conn.list_schemas_in_db(db) - schema_items: list[CatalogItem] = [] - for schema in schemas: - relations = self.conn.list_relations_in_schema(schema) - rel_items: list[CatalogItem] = [] - for rel, rel_type in relations: - cols = self.conn.list_columns_in_relation(rel) - col_items = [ - CatalogItem( - qualified_identifier=f'"{db}"."{schema}"."{rel}"."{col}"', - query_name=f'"{col}"', - label=col, - type_label=col_type, - ) - for col, col_type in cols - ] - rel_items.append( - CatalogItem( - qualified_identifier=f'"{db}"."{schema}"."{rel}"', - query_name=f'"{db}"."{schema}"."{rel}"', - label=rel, - type_label=rel_type, - children=col_items, - ) - ) - schema_items.append( - CatalogItem( - qualified_identifier=f'"{db}"."{schema}"', - query_name=f'"{db}"."{schema}"', - label=schema, - type_label="s", - children=rel_items, - ) - ) - db_items.append( - CatalogItem( - qualified_identifier=f'"{db}"', - query_name=f'"{db}"', - label=db, - type_label="db", - children=schema_items, - ) - ) - return Catalog(items=db_items) - - def get_completions(self) -> list[HarlequinCompletion]: - extra_keywords = ["foo", "bar", "baz"] - return [ - HarlequinCompletion( - label=item, type_label="kw", value=item, priority=1000, context=None - ) - for item in extra_keywords - ] - - -class MyAdapter(HarlequinAdapter): - ADAPTER_OPTIONS = MYADAPTER_OPTIONS - - def __init__(self, conn_str: Sequence[str], **options: Any) -> None: - self.conn_str = conn_str - self.options = options - - def connect(self) -> MyConnection: - conn = MyConnection(self.conn_str, self.options) - return conn diff --git a/src/harlequin_myadapter/cli_options.py b/src/harlequin_myadapter/cli_options.py deleted file mode 100644 index d893c61..0000000 --- a/src/harlequin_myadapter/cli_options.py +++ /dev/null @@ -1,15 +0,0 @@ -from harlequin.options import ( - FlagOption, # noqa - ListOption, # noqa - PathOption, # noqa - SelectOption, # noqa - TextOption, -) - -foo = TextOption( - name="foo", - description="Help text goes here", - short_decls=["-f"], -) - -MYADAPTER_OPTIONS = [foo] diff --git a/src/harlequin_trino/__init__.py b/src/harlequin_trino/__init__.py new file mode 100644 index 0000000..8c73a30 --- /dev/null +++ b/src/harlequin_trino/__init__.py @@ -0,0 +1,3 @@ +from harlequin_trino.adapter import HarlequinTrinoAdapter + +__all__ = ["HarlequinTrinoAdapter"] diff --git a/src/harlequin_trino/adapter.py b/src/harlequin_trino/adapter.py new file mode 100644 index 0000000..6b5a6d3 --- /dev/null +++ b/src/harlequin_trino/adapter.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +from typing import Any + +from harlequin import ( + HarlequinAdapter, + HarlequinConnection, + HarlequinCursor, +) +from harlequin.autocomplete.completion import HarlequinCompletion +from harlequin.catalog import Catalog, CatalogItem +from harlequin.exception import HarlequinConnectionError, HarlequinQueryError +from textual_fastdatatable.backend import AutoBackendType + +from harlequin_trino.cli_options import TRINO_OPTIONS +from harlequin_trino.completions import load_completions +from trino.auth import BasicAuthentication +from trino.dbapi import connect + + +class HarlequinTrinoCursor(HarlequinCursor): + def __init__(self, cur: Any) -> None: + self.cur = cur + self._limit: int | None = None + + def columns(self) -> list[tuple[str, str]]: + assert self.cur.description is not None + return [(col[0], self._get_short_type(col[1])) for col in self.cur.description] + + def set_limit(self, limit: int) -> HarlequinTrinoCursor: + self._limit = limit + return self + + def fetchall(self) -> AutoBackendType: + try: + if self._limit is None: + return self.cur.fetchall() + else: + return self.cur.fetchmany(self._limit) + except Exception as e: + raise HarlequinQueryError( + msg=str(e), + title="Harlequin encountered an error while executing your query.", + ) from e + finally: + self.cur.close() + + @staticmethod + def _get_short_type(type_name: str) -> str: + MAPPING = { + "array": "[]", + "bigint": "##", + "boolean": "t/f", + "char": "s", + "date": "d", + "decimal": "#.#", + "double": "#.#", + "ipaddress": "ip", + "integer": "#", + "interval": "|-|", + "json": "{}", + "real": "#.#", + "smallint": "#", + "time": "t", + "timestamp": "ts", + "tinyint": "#", + "uuid": "uid", + "varchar": "t", + } + return MAPPING.get(type_name.split("(")[0].split(" ")[0], "?") + + +class HarlequinTrinoConnection(HarlequinConnection): + def __init__( + self, + *_: Any, + init_message: str = "", + options: dict[str, Any], + ) -> None: + self.init_message = init_message + modified_options = options.copy() + password = modified_options.pop("password") + auth = modified_options.pop("require_auth", "None") + sslcert = modified_options.pop("sslcert", None) + if auth == "password": + user = modified_options.get("user") + modified_options["auth"] = BasicAuthentication(user, password) + modified_options["http_scheme"] = "https" + modified_options["verify"] = sslcert if sslcert else False + try: + self.conn = connect(**modified_options) + except Exception as e: + raise HarlequinConnectionError( + msg=str(e), title="Harlequin could not connect to your database." + ) from e + + def execute(self, query: str) -> HarlequinCursor | None: + try: + cur = self.conn.cursor().execute(query) + except Exception as e: + raise HarlequinQueryError( + msg=str(e), + title="Harlequin encountered an error while executing your query.", + ) from e + return HarlequinTrinoCursor(cur) + + def get_catalog(self) -> Catalog: + catalogs = self._get_catalogs() + db_items: list[CatalogItem] = [] + for (catalog,) in catalogs: + schemas = self._get_schemas(catalog) + schema_items: list[CatalogItem] = [] + for (schema,) in schemas: + relations = self._get_relations(catalog, schema) + rel_items: list[CatalogItem] = [] + for rel, rel_type in relations: + cols = self._get_columns(catalog, schema, rel) + col_items = [ + CatalogItem( + qualified_identifier=f'"{catalog}"."{schema}"."{rel}"."{col}"', + query_name=f'"{col}"', + label=col, + type_label=self._get_short_col_type(col_type), + ) + for col, col_type in cols + ] + rel_items.append( + CatalogItem( + qualified_identifier=f'"{catalog}"."{schema}"."{rel}"', + query_name=f'"{catalog}"."{schema}"."{rel}"', + label=rel, + type_label=rel_type, + children=col_items, + ) + ) + schema_items.append( + CatalogItem( + qualified_identifier=f'"{catalog}"."{schema}"', + query_name=f'"{catalog}"."{schema}"', + label=schema, + type_label="s", + children=rel_items, + ) + ) + db_items.append( + CatalogItem( + qualified_identifier=f'"{catalog}', + query_name=f'"{catalog}"', + label=catalog, + type_label="c", + children=schema_items, + ) + ) + return Catalog(items=db_items) + + def _get_catalogs(self) -> list[tuple[str]]: + cur = self.conn.cursor() + cur.execute("SHOW CATALOGS") + results: list[tuple[str]] = cur.fetchall() + cur.close() + return [ + result for result in results if result[0] not in ["jmx", "memory", "system"] + ] + + def _get_schemas(self, catalog: str) -> list[tuple[str]]: + cur = self.conn.cursor() + cur.execute(f"SHOW SCHEMAS FROM {catalog}") + results: list[tuple[str]] = cur.fetchall() + cur.close() + return [result for result in results if result[0] != "information_schema"] + + def _get_relations(self, catalog: str, schema: str) -> list[tuple[str, str]]: + cur = self.conn.cursor() + query = f""" + SELECT + table_name, + case + when table_type like '%TABLE' then 't' + else 'v' + end as table_type + FROM "{catalog}".information_schema.tables + WHERE table_schema = '{schema}' + """ + cur.execute(query) + results: list[tuple[str, str]] = cur.fetchall() + cur.close() + return results + + def _get_columns( + self, catalog: str, schema: str, rel: str + ) -> list[tuple[str, str]]: + cur = self.conn.cursor() + query = f""" + SELECT + column_name, + data_type + FROM {catalog}.information_schema.columns + WHERE + table_schema = '{schema}' + and table_name = '{rel}' + """ + cur.execute(query) + results: list[tuple[str, str]] = cur.fetchall() + cur.close() + return results + + @staticmethod + def _get_short_col_type(type_name: str) -> str: + MAPPING = { + "array": "[]", + "bigint": "##", + "boolean": "t/f", + "char": "s", + "date": "d", + "decimal": "#.#", + "double": "#.#", + "ipaddress": "ip", + "integer": "#", + "interval": "|-|", + "json": "{}", + "real": "#.#", + "smallint": "#", + "time": "t", + "timestamp": "ts", + "tinyint": "#", + "uuid": "uid", + "varchar": "t", + } + return MAPPING.get(type_name.split("(")[0].split(" ")[0], "?") + + def get_completions(self) -> list[HarlequinCompletion]: + return load_completions() + + +class HarlequinTrinoAdapter(HarlequinAdapter): + ADAPTER_OPTIONS = TRINO_OPTIONS + + def __init__( + self, + host: str | None = None, + port: str | None = None, + user: str | None = None, + password: str | None = None, + require_auth: str | None = None, + sslcert: str | None = None, + **_: Any, + ) -> None: + self.options = { + "host": host, + "port": port, + "user": user, + "password": password, + "require_auth": require_auth, + "sslcert": sslcert, + } + + def connect(self) -> HarlequinTrinoConnection: + conn = HarlequinTrinoConnection(options=self.options) + return conn diff --git a/src/harlequin_trino/cli_options.py b/src/harlequin_trino/cli_options.py new file mode 100644 index 0000000..9fa051e --- /dev/null +++ b/src/harlequin_trino/cli_options.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from harlequin.options import ( + FlagOption, # noqa + ListOption, # noqa + PathOption, # noqa + SelectOption, # noqa + 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=("Hostname of the Trino coordinator"), + short_decls=["-h"], + default="localhost", +) + + +port = TextOption( + name="port", + description=("Port number to connect at the Trino coordinator."), + short_decls=["-p"], + default="8080", +) + + +user = TextOption( + name="user", + description=("Trino user name to connect as."), + short_decls=["-u", "--username", "-U"], + default="trino", +) + + +password = TextOption( + name="password", + description=("Password to be used if the server demands password authentication."), +) + + +require_auth = SelectOption( + name="require_auth", + description=( + "Specifies the authentication method that the client requires from the server. " + "If the server does not use the required method to authenticate the client, or " + "if the authentication handshake is not fully completed by the server, the " + "connection will fail." + ), + choices=["password", "none"], +) + +sslcert = PathOption( + name="sslcert", + description=("Specifies the file name of the client SSL certificate. "), +) + +TRINO_OPTIONS = [host, port, user, password, require_auth, sslcert] diff --git a/src/harlequin_trino/completions.py b/src/harlequin_trino/completions.py new file mode 100644 index 0000000..7fad79b --- /dev/null +++ b/src/harlequin_trino/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_trino/functions.tsv b/src/harlequin_trino/functions.tsv new file mode 100644 index 0000000..c3be6bf --- /dev/null +++ b/src/harlequin_trino/functions.tsv @@ -0,0 +1,406 @@ +Name Description Introduced Deprecated +abs() Absolute value +acos() Arc cosine +all_match() Returns true if all elements of the array match the given predicate +any_match() Returns true if the array contains one or more elements that match the given predicate +any_value() Return an arbitrary non-null input value +any_value() Return an arbitrary non-null input value +approx_distinct() +approx_most_frequent() +approx_percentile() +approx_set() +arbitrary() Return an arbitrary non-null input value +array_agg() return an array of values +array_distinct() Remove duplicate values from the given array +array_except() Returns an array of elements that are in the first array but not the second, without duplicates. +array_histogram() Return a map containing the counts of the elements in the array +array_intersect() Intersects elements of the two given arrays +array_join() Concatenates the elements of the given array using a delimiter and an optional string to replace nulls +array_max() Get maximum value of array +array_min() Get minimum value of array +array_position() Returns the position of the first occurrence of the given value in array (or 0 if not found) +array_remove() Remove specified values from the given array +array_sort() Sorts the given array in ascending order according to the natural ordering of its elements. +array_union() Union elements of the two given arrays +arrays_overlap() Returns true if arrays have common elements +asin() Arc sine +at_timezone() +atan() Arc tangent +atan2() Arc tangent of given fraction +avg() Calculates the average value +bar() +beta_cdf() Beta cdf given the a, b parameters and value +bing_tile() Creates a Bing tile from XY coordinates and zoom level +bing_tile_at() Given a (latitude, longitude) point, returns the containing Bing tile at the specified zoom level +bing_tile_coordinates() Given a Bing tile, returns XY coordinates of the tile +bing_tile_polygon() Given a Bing tile, returns the polygon representation of the tile +bing_tile_quadkey() Given a Bing tile, returns its QuadKey +bing_tile_zoom_level() Given a Bing tile, returns zoom level of the tile +bing_tiles_around() Given a (longitude, latitude) point, returns the surrounding Bing tiles at the specified zoom level +bit_count() Count number of set bits in 2's complement representation +bitwise_and() Bitwise AND in 2's complement arithmetic +bitwise_and_agg() +bitwise_left_shift() bitwise left shift +bitwise_not() Bitwise NOT in 2's complement arithmetic +bitwise_or() Bitwise OR in 2's complement arithmetic +bitwise_or_agg() +bitwise_right_shift() bitwise logical right shift +bitwise_right_shift_arithmetic() bitwise arithmetic right shift +bitwise_xor() Bitwise XOR in 2's complement arithmetic +bool_and() +bool_or() +cardinality() Returns the cardinality (length) of the array +cbrt() Cube root +ceil() Round up to nearest integer +ceiling() Round up to nearest integer +char2hexint() Returns the hexadecimal representation of the UTF-16BE encoding of the argument +checksum() Checksum of the given values +chr() Convert Unicode code point to a string +classify() +codepoint() Returns Unicode code point of a single character string +color() +combinations() Return n-element subsets from array +concat() Concatenates an element to an array +concat_ws() Concatenates elements using separator +contains() Determines whether given value exists in the array +contains_sequence() Determines whether an array contains a sequence, with the values in the exact order +convex_hull_agg() Returns a geometry that is the convex hull of all the geometries in the set. +corr() +cos() Cosine +cosh() Hyperbolic cosine +cosine_similarity() Cosine similarity between the given sparse vectors +count() Counts the non-null values +count_if() +covar_pop() +covar_samp() +crc32() Compute CRC-32 +cume_dist() +current_date() Current date +current_groups() Current groups of current user +current_timezone() Current time zone +date() +date_add() Add the specified amount of date to the given date +date_diff() Difference of the given dates in the given unit +date_format() Formats the given timestamp by the given format +date_parse() +date_trunc() Truncate to the specified precision in the session timezone +day() Day of the month of the given date +day_of_month() Day of the month of the given timestamp +day_of_week() Day of the week of the given date +day_of_year() Day of the year of the given timestamp +degrees() Converts an angle in radians to degrees +dense_rank() +dow() Day of the week of the given date +doy() Day of the year of the given date +e() Euler's number +element_at() Get element of array at given index +empty_approx_set() An empty HyperLogLog instance +evaluate_classifier_predictions() +every() +exp() Euler's number raised to the given power +features() +filter() Return array containing elements that match the given predicate +first_value() +flatten() Flattens the given array +floor() Round down to nearest integer +format_datetime() Formats the given time by the given format +format_number() Formats large number using a unit symbol +from_base() Convert a string in the given base to a number +from_base32() Decode base32 encoded binary data +from_base64() Decode base64 encoded binary data +from_base64url() Decode URL safe base64 encoded binary data +from_big_endian_32() Decode bigint value from a 32-bit 2's complement big endian varbinary +from_big_endian_64() Decode bigint value from a 64-bit 2's complement big endian varbinary +from_encoded_polyline() Decodes a polyline to a linestring +from_geojson_geometry() Returns a spherical geography from a GeoJSON string +from_hex() Decode hex encoded binary data +from_ieee754_32() Decode the 32-bit big-endian binary in IEEE 754 single-precision floating-point format +from_ieee754_64() Decode the 64-bit big-endian binary in IEEE 754 double-precision floating-point format +from_iso8601_date() +from_iso8601_timestamp() +from_iso8601_timestamp_nanos() +from_unixtime() +from_unixtime_nanos() +from_utf8() Decodes the UTF-8 encoded string +geometric_mean() +geometry_from_hadoop_shape() Returns a Geometry type object from Spatial Framework for Hadoop representation +geometry_invalid_reason() Returns the reason for why the input geometry is not valid. Returns null if the input is valid. +geometry_nearest_points() Return the closest points on the two geometries +geometry_to_bing_tiles() Given a geometry and a zoom level, returns the minimum set of Bing tiles that fully covers that geometry +geometry_union() Returns a geometry that represents the point set union of the input geometries. +geometry_union_agg() Returns a geometry that represents the point set union of the input geometries. +great_circle_distance() Calculates the great-circle distance between two points on the Earth's surface in kilometers +greatest() Get the largest of the given values +hamming_distance() Computes Hamming distance between two strings +hash_counts() +histogram() Count the number of times each value occurs +hmac_md5() Compute HMAC with MD5 +hmac_sha1() Compute HMAC with SHA1 +hmac_sha256() Compute HMAC with SHA256 +hmac_sha512() Compute HMAC with SHA512 +hour() Hour of the day of the given interval +human_readable_seconds() +index() Returns index of first occurrence of a substring (or 0 if not found) +infinity() Infinity +intersection_cardinality() +inverse_beta_cdf() Inverse of Beta cdf given a, b parameters and probability +inverse_normal_cdf() Inverse of normal cdf given a mean, std, and probability +is_finite() Test if value is finite +is_infinite() Test if value is infinite +is_json_scalar() +is_nan() Test if value is not-a-number +jaccard_index() +json_array_contains() +json_array_get() +json_array_length() +json_extract() +json_extract_scalar() +json_format() +json_parse() +json_size() +kurtosis() Returns the (excess) kurtosis of the argument +lag() +last_day_of_month() Last day of the month of the given date +last_value() +lead() +learn_classifier() +learn_libsvm_classifier() +learn_regressor() +least() Get the smallest of the given values +length() Count of code points of the given string +levenshtein_distance() Computes Levenshtein distance between two strings +line_interpolate_point() Returns a Point interpolated along a LineString at the fraction given. +line_interpolate_points() Returns an array of Points interpolated along a LineString. +line_locate_point() Returns a float between 0 and 1 representing the location of the closest point on the LineString to the given Point, as a fraction of total 2d line length. +listagg() concatenates the input values with the specified separator +ln() Natural logarithm +log() Logarithm to given base +log10() Logarithm to base 10 +log2() Logarithm to base 2 +lower() Converts the string to lower case +lpad() Pads a varbinary on the left +ltrim() Removes whitespace from the beginning of a string +luhn_check() Checks that a string of digits is valid according to the Luhn algorithm +make_set_digest() +map() Constructs a map from the given key/value arrays +map_agg() Aggregates all the rows (key/value pairs) into a single map +map_concat() Concatenates given maps +map_entries() Construct an array of entries from a given map +map_filter() return map containing entries that match the given predicate +map_from_entries() Construct a map from an array of entries +map_keys() Returns the keys of the given map(K,V) as an array +map_union() Aggregate all the maps into a single map +map_values() Returns the values of the given map(K,V) as an array +map_zip_with() Merge two maps into a single map by applying the lambda function to the pair of values with the same key +max() Returns the maximum values of the argument +max_by() Returns the values of the first argument associated with the maximum values of the second argument +md5() Compute md5 hash +merge() Merges the input quantile digests into a single quantile digest +merge_set_digest() +millisecond() Millisecond of the second of the given interval +min() Returns the minimum values of the argument +min_by() Returns the values of the first argument associated with the minimum values of the second argument +minute() Minute of the hour of the given interval +mod() Remainder of given quotient +month() Month of the year of the given date +multimap_agg() Aggregates all the rows (key/value pairs) into a single multimap +multimap_from_entries() Construct a multimap from an array of entries +murmur3() Compute murmur3 hash +nan() Constant representing not-a-number +ngrams() Return N-grams for the input +none_match() Returns true if all elements of the array don't match the given predicate +normal_cdf() Normal cdf given a mean, standard deviation, and value +normalize() Transforms the string to normalized form +now() Current timestamp with time zone +nth_value() +ntile() +numeric_histogram() +objectid() Mongodb ObjectId +objectid_timestamp() Timestamp from the given Mongodb ObjectId +parse_data_size() Converts data size string to bytes +parse_datetime() Parses the specified date/time by the given format +parse_duration() Convert duration string to an interval +parse_presto_data_size() Converts data size string to bytes +percent_rank() +pi() The constant Pi +pow() Value raised to the power of exponent +power() Value raised to the power of exponent +qdigest_agg() Returns a qdigest from the set of bigints +quantile_at_value() Given an input x between min/max values of qdigest, find which quantile is represented by that value +quarter() Quarter of the year of the given date +radians() Converts an angle in degrees to radians +rand() A pseudo-random number between 0 and value (exclusive) +random() A pseudo-random number between start and stop (exclusive) +rank() +reduce() Reduce elements of the array into a single value +reduce_agg() Reduce input elements into a single value +regexp_count() Returns the number of times that a pattern occurs in a string +regexp_extract() String extracted using the given pattern +regexp_extract_all() String(s) extracted using the given pattern +regexp_like() Returns whether the pattern is contained within the string +regexp_position() Returns the index of the matched substring +regexp_replace() Replaces substrings matching a regular expression using a lambda function +regexp_split() Returns array of strings split by pattern +regr_intercept() +regr_slope() +regress() +render() +replace() Greedily replaces occurrences of a pattern with a string +reverse() Returns an array which has the reversed order of the given array. +rgb() +round() Round to nearest integer +row_number() +rpad() Pads a varbinary on the right +rtrim() Removes whitespace from the end of a string +second() Second of the minute of the given interval +sequence() Sequence function to generate synthetic arrays +sha1() Compute sha1 hash +sha256() Compute sha256 hash +sha512() Compute sha512 hash +shuffle() Generates a random permutation of the given array. +sign() Signum +simplify_geometry() Returns a "simplified" version of the given geometry +sin() Sine +sinh() Hyperbolic sine +skewness() Returns the skewness of the argument +slice() Subsets an array given an offset (1-indexed) and length +soundex() Encodes a string into a Soundex value +spatial_partitioning() +spatial_partitions() Returns an array of spatial partition IDs for a given geometry +split() +split_part() Splits a string by a delimiter and returns the specified field (counting from one) +split_to_map() Creates a map using entryDelimiter and keyValueDelimiter +split_to_multimap() Creates a multimap by splitting a string into key/value pairs +spooky_hash_v2_32() Compute SpookyHashV2 32-bit hash +spooky_hash_v2_64() Compute SpookyHashV2 64-bit hash +sqrt() Square root +ST_Area() Returns the 2D Euclidean area of a geometry +ST_AsBinary() Returns the Well-Known Binary (WKB) representation of the geometry +ST_AsText() Returns the Well-Known Text (WKT) representation of the geometry +ST_Boundary() Returns the closure of the combinatorial boundary of this Geometry +ST_Buffer() Returns the geometry that represents all points whose distance from the specified geometry is less than or equal to the specified distance +ST_Centroid() Returns the Point value that is the mathematical centroid of a Geometry +ST_Contains() Returns TRUE if and only if no points of right lie in the exterior of left, and at least one point of the interior of left lies in the interior of right +ST_ConvexHull() Returns the minimum convex geometry that encloses all input geometries +ST_CoordDim() Return the coordinate dimension of the Geometry +ST_Crosses() Returns TRUE if the supplied geometries have some, but not all, interior points in common +ST_Difference() Returns the Geometry value that represents the point set difference of two geometries +ST_Dimension() Returns the inherent dimension of this Geometry object, which must be less than or equal to the coordinate dimension +ST_Disjoint() Returns TRUE if the Geometries do not spatially intersect - if they do not share any space together +ST_Distance() Returns the 2-dimensional cartesian minimum distance (based on spatial ref) between two geometries in projected units +ST_Distance() Returns the great-circle distance in meters between two SphericalGeography points. +ST_EndPoint() Returns the last point of a LINESTRING geometry as a Point +ST_Envelope() Returns the bounding rectangular polygon of a Geometry +ST_EnvelopeAsPts() Returns the lower left and upper right corners of bounding rectangular polygon of a Geometry +ST_Equals() Returns TRUE if the given geometries represent the same geometry +ST_ExteriorRing() Returns a line string representing the exterior ring of the POLYGON +ST_Geometries() Returns an array of geometries in the specified collection +ST_GeometryFromText() Returns a Geometry type object from Well-Known Text representation (WKT) +ST_GeometryN() Returns the geometry element at the specified index (indices started with 1) +ST_GeometryType() Returns the type of the geometry +ST_GeomFromBinary() Returns a Geometry type object from Well-Known Binary representation (WKB) +ST_InteriorRingN() Returns the interior ring element at the specified index (indices start at 1) +ST_InteriorRings() Returns an array of interior rings of a polygon +ST_Intersection() Returns the Geometry value that represents the point set intersection of two Geometries +ST_Intersects() Returns TRUE if the Geometries spatially intersect in 2D - (share any portion of space) and FALSE if they don't (they are Disjoint) +ST_IsClosed() Returns TRUE if the LineString or Multi-LineString's start and end points are coincident +ST_IsEmpty() Returns TRUE if this Geometry is an empty geometrycollection, polygon, point etc +ST_IsRing() Returns TRUE if and only if the line is closed and simple +ST_IsSimple() Returns TRUE if this Geometry has no anomalous geometric points, such as self intersection or self tangency +ST_IsValid() Returns true if the input geometry is well formed +ST_Length() Returns the length of a LineString or Multi-LineString using Euclidean measurement on a 2D plane (based on spatial ref) in projected units +ST_Length() Returns the great-circle length in meters of a linestring or multi-linestring on Earth's surface +ST_LineFromText() Returns a Geometry type LineString object from Well-Known Text representation (WKT) +ST_LineString() Returns a LineString from an array of points +ST_MultiPoint() Returns a multi-point geometry formed from input points +ST_NumGeometries() Returns the cardinality of the geometry collection +ST_NumInteriorRing() Returns the cardinality of the collection of interior rings of a polygon +ST_NumPoints() Returns the number of points in a Geometry +ST_Overlaps() Returns TRUE if the Geometries share space, are of the same dimension, but are not completely contained by each other +ST_Point() Returns a Geometry type Point object with the given coordinate values +ST_PointN() Returns the vertex of a linestring at the specified index (indices started with 1) +ST_Points() Returns an array of points in a geometry +ST_Polygon() Returns a Geometry type Polygon object from Well-Known Text representation (WKT) +ST_Relate() Returns TRUE if this Geometry is spatially related to another Geometry +ST_StartPoint() Returns the first point of a LINESTRING geometry as a Point +ST_SymDifference() Returns the Geometry value that represents the point set symmetric difference of two Geometries +ST_Touches() Returns TRUE if the geometries have at least one point in common, but their interiors do not intersect +ST_Union() Returns a geometry that represents the point set union of the input geometries. +ST_Within() Returns TRUE if the geometry A is completely inside geometry B +ST_X() Return the X coordinate of the point +ST_XMax() Returns X maxima of a bounding box of a Geometry +ST_XMin() Returns X minima of a bounding box of a Geometry +ST_Y() Return the Y coordinate of the point +ST_YMax() Returns Y maxima of a bounding box of a Geometry +ST_YMin() Returns Y minima of a bounding box of a Geometry +starts_with() Determine whether source starts with prefix or not +stddev() Returns the sample standard deviation of the argument +stddev_pop() Returns the population standard deviation of the argument +stddev_samp() Returns the sample standard deviation of the argument +strpos() Returns index of first occurrence of a substring (or 0 if not found) +substr() Suffix starting at given index +substring() Suffix starting at given index +sum() Calculates the sum over the input values +tan() Tangent +tanh() Hyperbolic tangent +tdigest_agg() +timestamp_objectid() Mongodb ObjectId from the given timestamp +timezone_hour() Time zone hour of the given time +timezone_minute() Time zone minute of the given time +to_base() Convert a number to a string in the given base +to_base32() Encode binary data as base32 +to_base64() Encode binary data as base64 +to_base64url() Encode binary data as base64 using the URL safe alphabet +to_big_endian_32() Encode value as a 32-bit 2's complement big endian varbinary +to_big_endian_64() Encode value as a 64-bit 2's complement big endian varbinary +to_char() Formats a timestamp +to_date() Converts a string to a DATE data type +to_encoded_polyline() Encodes a linestring or multipoint geometry to a polyline +to_geojson_geometry() Returns GeoJSON string based on the input spherical geography +to_geometry() Converts a SphericalGeography object to a Geometry object. +to_hex() Encode binary data as hex +to_ieee754_32() Encode value as a big endian varbinary according to IEEE 754 single-precision floating-point format +to_ieee754_64() Encode value as a big endian varbinary according to IEEE 754 double-precision floating-point format +to_iso8601() +to_milliseconds() +to_spherical_geography() Converts a Geometry object to a SphericalGeography object +to_timestamp() Converts a string to a TIMESTAMP data type +to_unixtime() +to_utf8() Encodes the string to UTF-8 +transform() Apply lambda to each element of the array +transform_keys() Apply lambda to each entry of the map and transform the key +transform_values() Apply lambda to each entry of the map and transform the value +translate() Translate characters from the source string based on original and translations strings +trim() Removes whitespace from the beginning and end of a string +trim_array() Remove elements from the end of array +truncate() Round to integer by dropping given number of digits after decimal point +typeof() Textual representation of expression type +upper() Converts the string to upper case +url_decode() Unescape a URL-encoded string +url_encode() Escape a string for use in URL query parameter names and values +url_extract_fragment() Extract fragment from url +url_extract_host() Extract host from url +url_extract_parameter() Extract query parameter from url +url_extract_path() Extract part from url +url_extract_port() Extract port from url +url_extract_protocol() Extract protocol from url +url_extract_query() Extract query from url +uuid() Generates a random UUID +value_at_quantile() Given an input q between [0, 1], find the value whose rank in the sorted sequence of the n values represented by the qdigest is qn. +values_at_quantiles() For each input q between [0, 1], find the value whose rank in the sorted sequence of the n values represented by the qdigest is qn. +var_pop() Returns the population variance of the argument +var_samp() Returns the sample variance of the argument +variance() Returns the sample variance of the argument +week() Week of the year of the given date +week_of_year() Week of the year of the given timestamp +width_bucket() The bucket number of a value given an array of bins +wilson_interval_lower() Binomial confidence interval lower bound using Wilson score +wilson_interval_upper() Binomial confidence interval upper bound using Wilson score +with_timezone() +word_stem() Returns the stem of a word in the English language +xxhash64() Compute xxhash64 hash +year() Year of the given date +year_of_week() Year of the ISO week of the given date +yow() Year of the ISO week of the given date +zip() Merges the given arrays, element-wise, into a single array of rows. +zip_with() Merge two arrays, element-wise, into a single array using the lambda function \ No newline at end of file diff --git a/src/harlequin_trino/keywords.csv b/src/harlequin_trino/keywords.csv new file mode 100644 index 0000000..d363771 --- /dev/null +++ b/src/harlequin_trino/keywords.csv @@ -0,0 +1,82 @@ +ALTER,False,False +AND,False,False +AS,False,False +BETWEEN,False,False +BY,False,False +CASE,False,False +CAST,False,False +CONSTRAINT,False,False +CREATE,False,False +CROSS,False,False +CUBE,False,False +CURRENT_CATALOG,False,False +CURRENT_DATE,False,False +CURRENT_PATH,False,False +CURRENT_ROLE,False,False +CURRENT_SCHEMA,False,False +CURRENT_TIME,False,False +CURRENT_TIMESTAMP,False,False +CURRENT_USER,False,False +DEALLOCATE,False,False +DELETE,False,False +DESCRIBE,False,False +DISTINCT,False,False +DROP,False,False +ELSE,False,False +END,False,False +ESCAPE,False,False +EXCEPT,False,False +EXECUTE,False,False +EXISTS,False,False +EXTRACT,False,False +FALSE,False,False +FOR,False,False +FROM,False,False +FULL,False,False +GROUP,False,False +GROUPING,False,False +HAVING,False,False +IN,False,False +INNER,False,False +INSERT,False,False +INTERSECT,False,False +INTO,False,False +IS,False,False +JOIN,False,False +JSON_ARRAY,False,False +JSON_EXISTS,False,False +JSON_OBJECT,False,False +JSON_QUERY,False,False +JSON_TABLE,False,False +JSON_VALUE,False,False +LEFT,False,False +LIKE,False,False +LISTAGG,False,False +LOCALTIME,False,False +LOCALTIMESTAMP,False,False +NATURAL,False,False +NORMALIZE,False,False +NOT,False,False +NULL,False,False +ON,False,False +OR,False,False +ORDER,False,False +OUTER,False,False +PREPARE,False,False +RECURSIVE,False,False +RIGHT,False,False +ROLLUP,False,False +SELECT,False,False +SKIP,False,False +TABLE,False,False +THEN,False,False +TRIM,False,False +TRUE,False,False +UESCAPE,False,False +UNION,False,False +UNNEST,False,False +USING,False,False +VALUES,False,False +WHEN,False,False +WHERE,False,False +WITH,False,False \ No newline at end of file diff --git a/src/harlequin_myadapter/py.typed b/src/harlequin_trino/py.typed similarity index 100% rename from src/harlequin_myadapter/py.typed rename to src/harlequin_trino/py.typed diff --git a/tests/test_adapter.py b/tests/test_adapter.py index 41af8ee..7aed047 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -1,69 +1,83 @@ import sys +from typing import Generator import pytest from harlequin.adapter import HarlequinAdapter, HarlequinConnection, HarlequinCursor from harlequin.catalog import Catalog, CatalogItem -from harlequin.exception import HarlequinConnectionError, HarlequinQueryError -from harlequin_myadapter.adapter import MyAdapter, MyConnection +from harlequin.exception import HarlequinQueryError +from harlequin_trino.adapter import HarlequinTrinoAdapter, HarlequinTrinoConnection from textual_fastdatatable.backend import create_backend +from trino.dbapi import connect + if sys.version_info < (3, 10): from importlib_metadata import entry_points else: from importlib.metadata import entry_points +@pytest.fixture +def trino_options() -> dict: + return {"host": "localhost", "port": 8080, "user": "trino"} + + def test_plugin_discovery() -> None: - PLUGIN_NAME = "my-adapter" + PLUGIN_NAME = "trino" eps = entry_points(group="harlequin.adapter") assert eps[PLUGIN_NAME] - adapter_cls = eps[PLUGIN_NAME].load() + adapter_cls = eps[PLUGIN_NAME].load() # type: ignore assert issubclass(adapter_cls, HarlequinAdapter) - assert adapter_cls == MyAdapter + assert adapter_cls == HarlequinTrinoAdapter -def test_connect() -> None: - conn = MyAdapter(conn_str=tuple()).connect() +def test_connect(trino_options: dict) -> None: + conn = HarlequinTrinoAdapter(**trino_options).connect() assert isinstance(conn, HarlequinConnection) -def test_init_extra_kwargs() -> None: - assert MyAdapter(conn_str=tuple(), foo=1, bar="baz").connect() - - -def test_connect_raises_connection_error() -> None: - with pytest.raises(HarlequinConnectionError): - _ = MyAdapter(conn_str=("foo",)).connect() +def test_init_extra_kwargs(trino_options: dict) -> None: + assert HarlequinTrinoAdapter(**trino_options, foo=1, bar="baz").connect() @pytest.fixture -def connection() -> MyConnection: - return MyAdapter(conn_str=tuple()).connect() - - -def test_get_catalog(connection: MyConnection) -> None: +def connection(trino_options: dict) -> Generator[HarlequinTrinoConnection, None, None]: + mytrinoconn = connect(**trino_options) + cur = mytrinoconn.cursor() + cur.execute("drop schema if exists my_catalog.my_schema cascade") + cur.execute("create schema my_catalog.my_schema") + cur.close() + conn = HarlequinTrinoAdapter(**trino_options).connect() + yield conn + cur = mytrinoconn.cursor() + cur.execute("drop schema if exists my_catalog.my_schema cascade") + cur.close() + + +def test_get_catalog(connection: HarlequinTrinoConnection) -> None: catalog = connection.get_catalog() assert isinstance(catalog, Catalog) assert catalog.items assert isinstance(catalog.items[0], CatalogItem) -def test_execute_ddl(connection: MyConnection) -> None: - cur = connection.execute("create table foo (a int)") - assert cur is None +def test_execute_ddl(connection: HarlequinTrinoConnection) -> None: + cur = connection.execute("CREATE TABLE my_catalog.my_schema.my_table (a int)") + assert cur is not None + data = cur.fetchall() + assert not data -def test_execute_select(connection: MyConnection) -> None: +def test_execute_select(connection: HarlequinTrinoConnection) -> None: cur = connection.execute("select 1 as a") assert isinstance(cur, HarlequinCursor) - assert cur.columns() == [("a", "##")] + 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_dupe_cols(connection: MyConnection) -> None: +def test_execute_select_dupe_cols(connection: HarlequinTrinoConnection) -> None: cur = connection.execute("select 1 as a, 2 as a, 3 as a") assert isinstance(cur, HarlequinCursor) assert len(cur.columns()) == 3 @@ -73,7 +87,7 @@ def test_execute_select_dupe_cols(connection: MyConnection) -> None: assert backend.row_count == 1 -def test_set_limit(connection: MyConnection) -> None: +def test_set_limit(connection: HarlequinTrinoConnection) -> 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) @@ -84,6 +98,6 @@ def test_set_limit(connection: MyConnection) -> None: assert backend.row_count == 2 -def test_execute_raises_query_error(connection: MyConnection) -> None: +def test_execute_raises_query_error(connection: HarlequinTrinoConnection) -> None: with pytest.raises(HarlequinQueryError): _ = connection.execute("selec;") diff --git a/trino/etc/catalog/my_catalog.properties b/trino/etc/catalog/my_catalog.properties new file mode 100644 index 0000000..55f507a --- /dev/null +++ b/trino/etc/catalog/my_catalog.properties @@ -0,0 +1,4 @@ +connector.name=postgresql +connection-url=jdbc:postgresql://db:5432/postgres +connection-user=postgres +connection-password=postgres diff --git a/trino/etc/config.properties b/trino/etc/config.properties new file mode 100644 index 0000000..90d6101 --- /dev/null +++ b/trino/etc/config.properties @@ -0,0 +1,6 @@ +#single node install config +coordinator=true +node-scheduler.include-coordinator=true +http-server.http.port=8080 +discovery.uri=http://localhost:8080 + diff --git a/trino/etc/jvm.config b/trino/etc/jvm.config new file mode 100644 index 0000000..d8d2170 --- /dev/null +++ b/trino/etc/jvm.config @@ -0,0 +1,11 @@ +-server +-Xmx1G +-XX:+UseG1GC +-XX:G1HeapRegionSize=32M +-XX:+ExplicitGCInvokesConcurrent +-XX:+HeapDumpOnOutOfMemoryError +-XX:+UseGCOverheadLimit +-XX:+ExitOnOutOfMemoryError +-XX:ReservedCodeCacheSize=256M +-Djdk.attach.allowAttachSelf=true +-Djdk.nio.maxCachedBufferSize=2000000 \ No newline at end of file diff --git a/trino/etc/log.properties b/trino/etc/log.properties new file mode 100644 index 0000000..a147dd9 --- /dev/null +++ b/trino/etc/log.properties @@ -0,0 +1,2 @@ +# Enable verbose logging from Presto +#io.prestosql=DEBUG \ No newline at end of file diff --git a/trino/etc/node.properties b/trino/etc/node.properties new file mode 100644 index 0000000..72cb8a0 --- /dev/null +++ b/trino/etc/node.properties @@ -0,0 +1,3 @@ +node.environment=docker +node.data-dir=/data/trino +plugin.dir=/usr/lib/trino/plugin \ No newline at end of file