From 8182b0ab804c9983ab1129e592cb97e237f81a18 Mon Sep 17 00:00:00 2001 From: Joshua Cold Date: Sat, 23 Aug 2025 20:40:12 -0600 Subject: [PATCH] feat: start testing with mini.nvim - trigger tests for linux, macos, multiple vim versions --- .github/workflows/tests.yaml | 53 ++++++ .gitignore | 3 + Makefile | 75 ++++++++ README.md | 6 +- .../pip_pyproject/pyproject.toml | 8 + .../python_projects/pip_pyproject/script.py | 8 + .../pip_requirements/requirements.txt | 1 + .../pip_requirements/script.py | 8 + examples/python_projects/uv/.python-version | 1 - examples/python_projects/uv/main.py | 2 - examples/python_projects/uv/pyproject.toml | 2 - examples/python_projects/uv/uv.lock | 161 +++++------------- lua/python/config.lua | 27 ++- lua/python/treesitter/commands.lua | 2 - lua/python/venv/create.lua | 4 +- lua/python/venv/detect.lua | 14 +- scripts/minimal_init.lua | 29 ++++ tests/_test_template.lua | 32 ++++ tests/test_config.lua | 43 +++++ tests/test_detect.lua | 106 ++++++++++++ tests/test_interpreters.lua | 34 ++++ tests/test_keymap.lua | 33 ++++ tests/test_luasnip.lua | 31 ++++ tests/test_uv.lua | 44 +++++ tests/test_venv_create.lua | 57 +++++++ 25 files changed, 644 insertions(+), 140 deletions(-) create mode 100644 .github/workflows/tests.yaml create mode 100644 Makefile create mode 100644 examples/python_projects/pip_pyproject/pyproject.toml create mode 100644 examples/python_projects/pip_pyproject/script.py create mode 100644 examples/python_projects/pip_requirements/requirements.txt create mode 100644 examples/python_projects/pip_requirements/script.py delete mode 100644 examples/python_projects/uv/.python-version create mode 100644 scripts/minimal_init.lua create mode 100644 tests/_test_template.lua create mode 100644 tests/test_config.lua create mode 100644 tests/test_detect.lua create mode 100644 tests/test_interpreters.lua create mode 100644 tests/test_keymap.lua create mode 100644 tests/test_luasnip.lua create mode 100644 tests/test_uv.lua create mode 100644 tests/test_venv_create.lua diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..9ee9faa --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,53 @@ +name: Neovim Plugin Tests +on: + pull_request: + paths: + - "Makefile" + - ".github/workflows/tests.yaml" + - "examples/**" + - "lua/**" + - "tests/**" + push: + paths: + - "Makefile" + - ".github/workflows/tests.yaml" + - "examples/**" + - "lua/**" + - "tests/**" + +env: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.actor }} + cancel-in-progress: true + +jobs: + build: + name: Run tests + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + neovim_version: ["v0.10.4", "v0.11.3", "nightly"] + include: + - os: macos-latest + neovim_version: v0.11.3 + # TODO include windows when I have access to test on a windows machine. + # - os: windows-latest + # neovim_version: v0.11.3 + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - name: Setup neovim + uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: ${{ matrix.neovim_version }} + + - name: Install uv + uses: astral-sh/setup-uv@v6 + + - name: Run tests + run: make test diff --git a/.gitignore b/.gitignore index 55e2090..e9ec938 100644 --- a/.gitignore +++ b/.gitignore @@ -214,3 +214,6 @@ cython_debug/ # PyPI configuration file .pypirc + +# test deps +deps/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..94af4cf --- /dev/null +++ b/Makefile @@ -0,0 +1,75 @@ +SHELL := /bin/bash +.ONESHELL: +.SILENT: + +# Run all test files +test: deps test_requirements + nvim --headless --noplugin -u ./scripts/minimal_init.lua -c "lua MiniTest.run()" + +# Run test from file at `$FILE` environment variable +test_file: deps test_requirements + nvim --headless --noplugin -u ./scripts/minimal_init.lua -c "lua MiniTest.run_file('$(FILE)')" + +# Install all test dependencies +deps: deps/mini.nvim \ + deps/nvim-dap \ + deps/nvim-dap-python \ + deps/nvim-lspconfig \ + deps/nui.nvim \ + deps/LuaSnip \ + deps/neotest \ + deps/neotest-python \ + deps/nvim-treesitter + +test_requirements: + for req in "python3" "uv"; do \ + command -v "$$req" > /dev/null || { echo "system cmd '$$req' required for tests"; exit 1; } ;\ + done + for req in "venv"; do \ + python3 -c "import $$req" || { echo "python dependency '$$req' required for tests"; exit 1; } ;\ + done + +deps/nvim-treesitter: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/nvim-treesitter/nvim-treesitter $@ + +deps/mini.nvim: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/echasnovski/mini.nvim $@ + +deps/nvim-dap: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/mfussenegger/nvim-dap $@ + +deps/nvim-dap-python: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/mfussenegger/nvim-dap-python $@ + +deps/nvim-lspconfig: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/neovim/nvim-lspconfig $@ + +deps/nui.nvim: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/MunifTanjim/nui.nvim $@ + +deps/LuaSnip: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/L3MON4D3/LuaSnip $@ + +deps/neotest: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/nvim-neotest/neotest $@ + +deps/neotest-python: + set -x + @mkdir -p deps + git clone --filter=blob:none https://github.com/nvim-neotest/neotest-python $@ diff --git a/README.md b/README.md index 207d380..54ab6bc 100644 --- a/README.md +++ b/README.md @@ -289,12 +289,12 @@ return { - [x] Linux -- [x] MacOS (Mostly should work) +- [x] MacOS - - [x] I am detecting python interpreters in homebrew and hatch. Does the community use other methods of installing python? + - [x] I am detecting python interpreters in homebrew and hatch and uv. Testing in ci. - [ ] Windows (Un tested) - - [ ] Most likely spots where we are mixing up `/` vs `\` in paths + - [ ] Need to test this plugin on a windows machine to verify. I have seen online that neovim users are deciding on WezTerm + WSL to handle support for neovim plugins. ## Special Thanks diff --git a/examples/python_projects/pip_pyproject/pyproject.toml b/examples/python_projects/pip_pyproject/pyproject.toml new file mode 100644 index 0000000..93f1dcd --- /dev/null +++ b/examples/python_projects/pip_pyproject/pyproject.toml @@ -0,0 +1,8 @@ +[project] +name = "test" +dependencies = [ + "boto3" +] +version = "0.1.0" +requires-python = ">=3.12" +description = "A short description of my awesome Python package." diff --git a/examples/python_projects/pip_pyproject/script.py b/examples/python_projects/pip_pyproject/script.py new file mode 100644 index 0000000..6a19a83 --- /dev/null +++ b/examples/python_projects/pip_pyproject/script.py @@ -0,0 +1,8 @@ +import boto3 + +def main(): + print() + + +if __name__ == "__main__": + main() diff --git a/examples/python_projects/pip_requirements/requirements.txt b/examples/python_projects/pip_requirements/requirements.txt new file mode 100644 index 0000000..30ddf82 --- /dev/null +++ b/examples/python_projects/pip_requirements/requirements.txt @@ -0,0 +1 @@ +boto3 diff --git a/examples/python_projects/pip_requirements/script.py b/examples/python_projects/pip_requirements/script.py new file mode 100644 index 0000000..6a19a83 --- /dev/null +++ b/examples/python_projects/pip_requirements/script.py @@ -0,0 +1,8 @@ +import boto3 + +def main(): + print() + + +if __name__ == "__main__": + main() diff --git a/examples/python_projects/uv/.python-version b/examples/python_projects/uv/.python-version deleted file mode 100644 index e4fba21..0000000 --- a/examples/python_projects/uv/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/examples/python_projects/uv/main.py b/examples/python_projects/uv/main.py index 66aa5d8..7aa4e06 100644 --- a/examples/python_projects/uv/main.py +++ b/examples/python_projects/uv/main.py @@ -1,6 +1,4 @@ import requests -import boto3 -import redis def main(): print("Hello from uv!") diff --git a/examples/python_projects/uv/pyproject.toml b/examples/python_projects/uv/pyproject.toml index cabe89c..a42d64c 100644 --- a/examples/python_projects/uv/pyproject.toml +++ b/examples/python_projects/uv/pyproject.toml @@ -5,7 +5,5 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.12" dependencies = [ - "boto3>=1.37.23", - "redis>=5.2.1", "requests>=2.32.3", ] diff --git a/examples/python_projects/uv/uv.lock b/examples/python_projects/uv/uv.lock index e1790f9..f4ba66c 100644 --- a/examples/python_projects/uv/uv.lock +++ b/examples/python_projects/uv/uv.lock @@ -1,116 +1,58 @@ version = 1 -revision = 1 +revision = 3 requires-python = ">=3.12" -[[package]] -name = "boto3" -version = "1.37.23" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "botocore" }, - { name = "jmespath" }, - { name = "s3transfer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/65/81/fcaf72cf86c4b3f1a4efa3500e08c97d2a98966a35760acfaed79100c6a0/boto3-1.37.23.tar.gz", hash = "sha256:82f4599a34f5eb66e916b9ac8547394f6e5899c19580e74b60237db04cf66d1e", size = 111354 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/eb/88fe910bde6ccc94cbf099bc5e50b7bf79c97a3292bb4e0e2fbd73824906/boto3-1.37.23-py3-none-any.whl", hash = "sha256:fc462b9fd738bd8a1c121d94d237c6b6a05a2c1cc709d16f5223acb752f7310b", size = 139561 }, -] - -[[package]] -name = "botocore" -version = "1.37.23" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jmespath" }, - { name = "python-dateutil" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0e/34/9becaddf187353e1449a3bfa08ee7b069398f51e3d600cffdb0a63789e34/botocore-1.37.23.tar.gz", hash = "sha256:3a249c950cef9ee9ed7b2278500ad83a4ad6456bc433a43abd1864d1b61b2acb", size = 13680710 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/1c/9d840859acaf6df9effa9ef3e25624c27fc65334c51396909b22e235e8d1/botocore-1.37.23-py3-none-any.whl", hash = "sha256:ffbe1f5958adb1c50d72d3ad1018cb265fe349248c08782d334601c0814f0e38", size = 13446175 }, -] - [[package]] name = "certifi" version = "2025.1.31" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577, upload-time = "2025-01-31T02:16:47.166Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393, upload-time = "2025-01-31T02:16:45.015Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } +sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188, upload-time = "2024-12-24T18:12:35.43Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, - { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, - { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, - { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, - { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, - { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, - { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, - { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, - { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, - { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, - { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, - { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, - { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, - { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, - { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, - { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, - { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, - { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, - { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, - { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, - { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, - { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, - { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, - { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, - { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, - { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, - { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, + { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105, upload-time = "2024-12-24T18:10:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404, upload-time = "2024-12-24T18:10:44.272Z" }, + { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423, upload-time = "2024-12-24T18:10:45.492Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184, upload-time = "2024-12-24T18:10:47.898Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268, upload-time = "2024-12-24T18:10:50.589Z" }, + { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601, upload-time = "2024-12-24T18:10:52.541Z" }, + { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098, upload-time = "2024-12-24T18:10:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520, upload-time = "2024-12-24T18:10:55.048Z" }, + { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852, upload-time = "2024-12-24T18:10:57.647Z" }, + { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488, upload-time = "2024-12-24T18:10:59.43Z" }, + { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192, upload-time = "2024-12-24T18:11:00.676Z" }, + { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550, upload-time = "2024-12-24T18:11:01.952Z" }, + { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785, upload-time = "2024-12-24T18:11:03.142Z" }, + { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698, upload-time = "2024-12-24T18:11:05.834Z" }, + { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162, upload-time = "2024-12-24T18:11:07.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263, upload-time = "2024-12-24T18:11:08.374Z" }, + { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966, upload-time = "2024-12-24T18:11:09.831Z" }, + { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992, upload-time = "2024-12-24T18:11:12.03Z" }, + { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162, upload-time = "2024-12-24T18:11:13.372Z" }, + { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972, upload-time = "2024-12-24T18:11:14.628Z" }, + { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095, upload-time = "2024-12-24T18:11:17.672Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668, upload-time = "2024-12-24T18:11:18.989Z" }, + { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073, upload-time = "2024-12-24T18:11:21.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732, upload-time = "2024-12-24T18:11:22.774Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391, upload-time = "2024-12-24T18:11:24.139Z" }, + { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702, upload-time = "2024-12-24T18:11:26.535Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767, upload-time = "2024-12-24T18:12:32.852Z" }, ] [[package]] name = "idna" version = "3.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, -] - -[[package]] -name = "jmespath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, -] - -[[package]] -name = "redis" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/da/d283a37303a995cd36f8b92db85135153dc4f7a8e4441aa827721b442cfb/redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f", size = 4608355 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/5f/fa26b9b2672cbe30e07d9a5bdf39cf16e3b80b42916757c5f92bca88e4ba/redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4", size = 261502 }, + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, ] [[package]] @@ -123,39 +65,18 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - -[[package]] -name = "s3transfer" -version = "0.11.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "botocore" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/ec/aa1a215e5c126fe5decbee2e107468f51d9ce190b9763cb649f76bb45938/s3transfer-0.11.4.tar.gz", hash = "sha256:559f161658e1cf0a911f45940552c696735f5c74e64362e515f333ebed87d679", size = 148419 } +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/62/8d3fc3ec6640161a5649b2cddbbf2b9fa39c92541225b33f117c37c5a2eb/s3transfer-0.11.4-py3-none-any.whl", hash = "sha256:ac265fa68318763a03bf2dc4f39d5cbd6a9e178d81cc9483ad27da33637e320d", size = 84412 }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, ] [[package]] name = "urllib3" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" }, ] [[package]] @@ -163,14 +84,8 @@ name = "uv" version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "boto3" }, - { name = "redis" }, { name = "requests" }, ] [package.metadata] -requires-dist = [ - { name = "boto3", specifier = ">=1.37.23" }, - { name = "redis", specifier = ">=5.2.1" }, - { name = "requests", specifier = ">=2.32.3" }, -] +requires-dist = [{ name = "requests", specifier = ">=2.32.3" }] diff --git a/lua/python/config.lua b/lua/python/config.lua index 0b6e6cb..40f017a 100644 --- a/lua/python/config.lua +++ b/lua/python/config.lua @@ -109,10 +109,35 @@ local defaults = { } } +-- Only for existing keys in `target`. +local function tbl_deep_extend_existing(target, source, prev_key) + -- Return if source or target is not a table or is nil + if type(target) ~= "table" or type(source) ~= "table" then + return target + end + + for key, value in pairs(source) do + -- Only update keys that already exist in the target table + if target[key] ~= nil then + if type(target[key]) == "table" and type(value) == "table" then + prev_key = prev_key .. "." .. key + -- Recurse for nested tables + tbl_deep_extend_existing(target[key], value, prev_key) + else + -- Overwrite existing key + target[key] = value + end + else + error(("python.nvim: user inputted config key: %s is not found in config table: %s"):format(key, prev_key)) + end + end + return target +end + ---@param opts? python.Config function M.setup(opts) opts = opts or {} - M.config = vim.tbl_deep_extend('force', defaults, opts) + M.config = tbl_deep_extend_existing(defaults, opts, "config") end return setmetatable(M, { diff --git a/lua/python/treesitter/commands.lua b/lua/python/treesitter/commands.lua index 62b5dcf..8359ed9 100644 --- a/lua/python/treesitter/commands.lua +++ b/lua/python/treesitter/commands.lua @@ -1,7 +1,5 @@ -- Utility functions and commands utilizing treesitter local M = {} -local nodes = require('python.treesitter.nodes') -local ts = require('python.treesitter') local config = require('python.config') ---get node at cursor and validate that the user has at least nvim 0.9 diff --git a/lua/python/venv/create.lua b/lua/python/venv/create.lua index ef5d753..95b6975 100644 --- a/lua/python/venv/create.lua +++ b/lua/python/venv/create.lua @@ -283,7 +283,7 @@ end ---Create the python venv with selected interpreter" ---@param venv_path string path of venv to create ---@param python_interpreter string path to python executable to use -local function create_venv_with_python(venv_path, python_interpreter) +function M.create_venv_with_python(venv_path, python_interpreter) vim.notify_once('python.nvim: creating venv at: ' .. venv_path, vim.log.levels.INFO) local cmd = { python_interpreter, '-m', 'venv', venv_path } vim.system( @@ -389,7 +389,7 @@ local function venv_install_file(detect) return end - create_venv_with_python(venv_path_user_input, python_interpreter_user_input) + M.create_venv_with_python(venv_path_user_input, python_interpreter_user_input) install_function(detect.venv.install_file, venv_path_user_input, function() local val = { diff --git a/lua/python/venv/detect.lua b/lua/python/venv/detect.lua index 0524554..fc9e8f2 100644 --- a/lua/python/venv/detect.lua +++ b/lua/python/venv/detect.lua @@ -2,6 +2,7 @@ local state = require("python.state") local create = require("python.venv.create") local M = {} +local IS_WINDOWS = vim.uv.os_uname().sysname == 'Windows_NT' ---@class DetectVEnv ---@field dir string Current working directory found containing venv @@ -119,12 +120,12 @@ function M.search_up(dir_or_file) local dir_to_check = nil -- get parent directory of current file in buffer via vim expand local dir_template = '%:p:h' - while not found and dir_to_check ~= '/' do + while not found and (dir_to_check ~= '/' or dir_to_check ~= "C:\\" or dir_to_check ~= "D:\\") do dir_to_check = vim.fn.expand(dir_template) - local check_path = dir_to_check .. '/' .. dir_or_file - local check_git = dir_to_check .. '/' .. '.git' + local check_path = vim.fs.joinpath(dir_to_check, dir_or_file) + local check_git = vim.fs.joinpath(dir_to_check, '.git') if vim.fn.isdirectory(check_path) == 1 or vim.fn.filereadable(check_path) == 1 then - found = dir_to_check .. '/' .. dir_or_file + found = vim.fs.joinpath(dir_to_check, dir_or_file) else dir_template = dir_template .. ':h' end @@ -155,6 +156,11 @@ function M.search_for_detected_type() if check_type == "pattern" then if vim.fn.search(search) ~= 0 then local found = vim.api.nvim_buf_get_name(0) + -- Go through join path to get / slashes to be consistent in windows like + -- we get with M.search_up + if IS_WINDOWS then + found = vim.fs.joinpath(vim.fs.dirname(found), vim.fs.basename(found)) + end return found, search end end diff --git a/scripts/minimal_init.lua b/scripts/minimal_init.lua new file mode 100644 index 0000000..27f4f3c --- /dev/null +++ b/scripts/minimal_init.lua @@ -0,0 +1,29 @@ +-- Add current directory to 'runtimepath' to be able to use 'lua' files +vim.cmd([[let &rtp.=','.getcwd()]]) + +-- Set up 'mini.test' only when calling headless Neovim (like with `make test`) +if #vim.api.nvim_list_uis() == 0 then + -- Add 'mini.nvim' to 'runtimepath' to be able to use 'mini.test' + -- Assumed that 'mini.nvim' is stored in 'deps/mini.nvim' + -- + local runtime_dependencies = { + "deps/mini.nvim", + "deps/nui.nvim", + "deps/nvim-treesitter", + "deps/neotest", + "deps/neotest-python", + "deps/nvim-dap", + "deps/nvim-dap-python", + "deps/nvim-lspconfig", + "deps/LuaSnip", + } + local runtime_path = vim.fn.join(runtime_dependencies, ",") + vim.cmd('set rtp+=' .. runtime_path) + + -- Set up 'mini.test' + require('nui.popup') + require('luasnip.extras.fmt') + require('luasnip.nodes.absolute_indexer') + require('nvim-treesitter.locals') + require('mini.test').setup() +end diff --git a/tests/_test_template.lua b/tests/_test_template.lua new file mode 100644 index 0000000..2e479cd --- /dev/null +++ b/tests/_test_template.lua @@ -0,0 +1,32 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[require('python').setup()]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +-- T['works'] = function() +-- local x = 1 + 1 +-- if x ~= 2 then +-- error('`x` is not equal to 2') +-- end +-- end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_config.lua b/tests/test_config.lua new file mode 100644 index 0000000..860c974 --- /dev/null +++ b/tests/test_config.lua @@ -0,0 +1,43 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[config = require('python.config')]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +T['setup'] = MiniTest.new_set() + +T['setup']['init'] = function() + child.lua('config.setup({})') + eq(child.lua('return config.python_lua_snippets'), false) +end + +T['setup']['override'] = function() + child.lua('config.setup({ python_lua_snippets = true })') + eq(child.lua('return config.python_lua_snippets'), true) +end + +T['setup']['not_found'] = function() + expect.error(function() + child.lua('config.setup({ ui = { popup = {foobar = true}} })') + end, ".*user inputted config key: foobar is not found.*") +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_detect.lua b/tests/test_detect.lua new file mode 100644 index 0000000..a96ab53 --- /dev/null +++ b/tests/test_detect.lua @@ -0,0 +1,106 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +--- expect to detect wanted methods per project. +T['detect'] = MiniTest.new_set({ + parametrize = { + { + { + project_path = "examples/python_projects/pip_requirements", + install_file = "requirements.txt", + dependency_method = "requirements.txt" + } + }, + { + { + project_path = "examples/python_projects/pip_pyproject", + install_file = "pyproject.toml", + dependency_method = "pyproject.toml" + } + }, + { + { + project_path = "examples/python_projects/uv", + install_file = "uv.lock", + dependency_method = "uv.lock" + } + }, + { + { + project_path = "examples/python_projects/poetry", + install_file = "poetry.lock", + dependency_method = "poetry.lock" + } + }, + { + { + project_path = "examples/python_projects/uv_script", + install_file = "uv-script.py", + dependency_method = "/// script" + } + }, + { + { + project_path = "examples/python_projects/no_dep", + install_file = "test.py", + dependency_method = "", + expect_nil = true + } + }, + } +}) + +T['detect']['methods'] = function(args) + require("python.venv.detect") + local project_path = args.project_path + child.cmd("cd " .. project_path) + child.cmd([[!rm -rf .venv]]) + child.cmd("e " .. args.install_file) + child.lua([[detect = require('python.venv.detect')]]) + + -- Get abspath in lua for older versions of neovim + local abspath = child.lua("return vim.fn.expand('%:p:h')") + + -- Weird vim.fs.joinpath in test is meant to have vim output the same pathing + -- format that happens in windows from joinpath in detect_venv_dependency_file + if vim.uv.os_uname().sysname == 'Windows_NT' then + abspath = vim.fs.joinpath(vim.fs.dirname(child.lua("return vim.fn.expand('%:p:h')")), + vim.fs.basename(args.project_path)) + end + + ---@type DetectVEnv | vim.NIL + local ex = DetectVEnv:new({ + dir = abspath, + venv = { + install_file = vim.fs.joinpath(abspath, args.install_file), + install_method = args.dependency_method, + source = "venv" + } + }) + if args.expect_nil then + ex = vim.NIL + end + + eq(child.lua([[ return detect.detect_venv_dependency_file(false, false) ]]), ex) +end + +return T diff --git a/tests/test_interpreters.lua b/tests/test_interpreters.lua new file mode 100644 index 0000000..a62b105 --- /dev/null +++ b/tests/test_interpreters.lua @@ -0,0 +1,34 @@ + +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[require('python').setup()]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +T['interpreters'] = MiniTest.new_set() + +T['interpreters']['python'] = function() + child.lua("inter = require('python.venv.interpreters')") + local pythons = child.lua("return inter.python_interpreters()") + assert(#pythons > 0) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_keymap.lua b/tests/test_keymap.lua new file mode 100644 index 0000000..0372df3 --- /dev/null +++ b/tests/test_keymap.lua @@ -0,0 +1,33 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[require('python').setup()]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +-- Keymaps can be loaded +T['keymaps'] = function() + child.cmd("cd examples/python_projects/uv") + child.cmd("e main.py") + local keymap = child.cmd_capture("map pi") + assert(string.find(keymap, "python venv install", 1, true)) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_luasnip.lua b/tests/test_luasnip.lua new file mode 100644 index 0000000..b18f534 --- /dev/null +++ b/tests/test_luasnip.lua @@ -0,0 +1,31 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[require('python').setup({ python_lua_snippets = true })]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +T['snips will load'] = function() + child.lua([[M = require('python.snip')]]) + child.lua([[M.load_snippets()]]) + eq(child.lua([[return vim.g._python_nvim_snippets_loaded]]), true) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_uv.lua b/tests/test_uv.lua new file mode 100644 index 0000000..d012124 --- /dev/null +++ b/tests/test_uv.lua @@ -0,0 +1,44 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[require('python').setup()]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) +T['uv'] = MiniTest.new_set({ + hooks = { + pre_case = function() + end + } +}) + +T['uv']['command'] = function() + child.cmd("cd examples/python_projects/uv") + child.cmd("e main.py") + child.cmd([[!rm -rf .venv]]) + child.cmd([[UV sync]]) + local dir = child.lua("return vim.fn.expand('%:p:h')") + local venv_dir = vim.fs.joinpath(dir, ".venv") + + -- give some seconds for uv sync to download package + vim.loop.sleep(3000) + eq(child.lua(("return vim.fn.isdirectory('%s')"):format(venv_dir)), 1) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_venv_create.lua b/tests/test_venv_create.lua new file mode 100644 index 0000000..ca91eb2 --- /dev/null +++ b/tests/test_venv_create.lua @@ -0,0 +1,57 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ '-u', 'scripts/minimal_init.lua' }) + -- Load tested plugin + child.lua([[require('python').setup({})]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + + +T['create'] = MiniTest.new_set({ n_retry = 3 }) + +-- NOTE: requires python3 and python3-venv installed on system +T['create']['venv'] = function() + child.lua("create = require('python.venv.create')") + child.cmd("cd examples/python_projects/uv") + child.cmd("!rm -rf .venv") + child.cmd("e main.py") + child.lua("create.create_venv_with_python('.venv', 'python3')") + assert(vim.fn.isdirectory("examples/python_projects/uv/.venv") == 1) + child.cmd("!rm -rf .venv") +end + +-- NOTE: requires uv installed on system +T['create']['uv_sync'] = function() + child.lua("create = require('python.venv.create')") + child.cmd("cd examples/python_projects/uv") + child.cmd("!rm -rf .venv") + child.cmd("e main.py") + child.lua("create.create_venv_with_python('.venv', 'python3')") + child.lua("create.uv_sync('uv.lock', '.venv', function()end, false)") + + local dep_path = vim.fn.system( + [[examples/python_projects/uv/.venv/bin/python -c 'import sys; print(sys.path[-1], end="")']]) + + assert(string.find(dep_path, "python_projects", 1, true)) + + local check_dir = vim.fs.joinpath(dep_path, "requests") + eq(vim.fn.isdirectory(check_dir), 1) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T