Skip to content

feat: Nvim can detect venv python via "pynvim-python" tool #594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,35 @@ Install

Supports python 3.7 or later.

pip3 install pynvim
- Installation option #1: install using uv (recommended):

You can install the package without being root by adding the `--user` flag.
Anytime you upgrade Neovim, make sure to upgrade pynvim as well:
- Install uv (https://docs.astral.sh/uv/).

pip3 install --upgrade pynvim
- Install pynvim (the `--upgrade` switch ensures installation of the latest
version):

Alternatively, you can install the development version by cloning this
repository and executing the following at the top level:
uv tool install --upgrade pynvim

pip3 install .
- Anytime you upgrade Neovim, make sure to upgrade pynvim as well by
re-running the above command.

- Installation option #2: install using pipx:

- Install pipx (https://pipx.pypa.io/stable/).

- Install pynvim (the `--upgrade` switch ensures installation of the latest
version):

pipx install --upgrade pynvim

- Anytime you upgrade Neovim, make sure to upgrade pynvim as well by
re-running the above command.

- Other installation options:

- See [pynvim installation
documentation](https://pynvim.readthedocs.io/en/latest/installation.html)
for additional installation options and information.

Python Plugin API
-----------------
Expand Down
128 changes: 119 additions & 9 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,63 @@ Installation

The Neovim Python client supports Python 3.7 or later.

Using pip
---------
Using uv or pipx
----------------

You can install the package without being root by adding the ``--user`` flag::
For automatic detection by Neovim, pynvim should be installed in a dedicated
Python virtual environment and the ``pynvim-python`` executable should be placed
on the ``PATH``. The recommended approach for this is to use a tool like uv
(https://docs.astral.sh/uv/) or pipx (https://pipx.pypa.io/stable/); the
``--upgrade`` switch ensures installation of the latest version:

pip3 install --user pynvim
- Install using uv (recommended)::

If you follow Neovim HEAD, make sure to upgrade ``pynvim`` when you upgrade
Neovim::
uv tool install --upgrade pynvim

pip3 install --upgrade pynvim
- Install using pipx::

pipx install --upgrade pynvim

**NOTE** For Neovim before v0.12.0, set the variable ``python3_host_prog`` in
``init.vim`` to point to ``pynvim-python``::

let g:python3_host_prog = 'pynvim-python'

Using manually created Python virtual environment
-------------------------------------------------

Alternatively, you may manually create a Python virtual environment
(https://docs.python.org/3.13/library/venv.html)::

python3 -m venv pynvim-venv

Then install pynvim into the virtual environment; the
``--upgrade`` switch ensures installation of the latest version::

- For Unix::

pynvim-venv/bin/python -m pip install --upgrade pynvim

- For Windows::

pynvim-venv\Scripts\python -m pip install --upgrade pynvim

Then copy the ``pynvim-python`` executable somewhere on the ``PATH``:

- For Unix::

# Assuming `~/.local/bin` is on `PATH`:
cp pynvim-venv/bin/pynvim-python ~/.local/bin/pynvim-python

- For Windows::

REM Assuming `C:\apps` is on `PATH`:
copy pynvim-venv\Scripts\pynvim-python.exe C:\apps\pynvim-python.exe

**NOTE** For Neovim before v0.12.0, set the variable ``python3_host_prog`` in
``init.vim`` to point to ``pynvim-python``::

let g:python3_host_prog = 'pynvim-python'

Install from source
-------------------
Expand All @@ -23,6 +69,70 @@ Clone the repository somewhere on your disk and enter to the repository::
git clone https://github.com/neovim/pynvim.git
cd pynvim

Now you can install it on your system::
Now you can install it following the instructions above, using ``.`` instead of
``pynvim``; the ``--upgrade`` switch ensures installation of the latest version:

- Install from source using uv::

uv tool install --upgrade .

- Install from source using pipx::

pipx install --upgrade .

- Install from source using manually created Python virtual environment:

- Create ``pynvim-venv`` as above.

- Install:

- For Unix::

pynvim-venv/bin/python -m pip install --upgrade .

- For Windows::

pynvim-venv\Scripts\python -m pip install --upgrade .

- Copy ``pynvim-python`` executable as above.

**NOTE** For Neovim before v0.12.0, set the variable ``python3_host_prog`` in
``init.vim`` to point to ``pynvim-python``::

let g:python3_host_prog = 'pynvim-python'

Upgrade pynvim when upgrading Neovim
------------------------------------

Make sure to upgrade ``pynvim`` when you upgrade Neovim. Follow the previous
instructions; the ``--upgrade`` switch will ensure installation of the latest
version.

Explicitly choosing pynvim virtual environment
----------------------------------------------

As an alternative to exposing ``pynvim-python`` on ``PATH``, you may configure
Neovim to use a specific Python interpreter that has pynvim installed; this may
be useful when working on pynvim itself.

After installing into a virtual environment named ``pynvim-venv``, add the
following into Neovim's ``init.vim`` file:

- For Unix::

let g:python3_host_prog = '/path/to/pynvim-venv/bin/python'

- For Windows::

let g:python3_host_prog = 'c:\path\to\pynvim-venv\bin\python.exe'

Installing outside of a virtual environment is deprecated
---------------------------------------------------------

Installing into the per-user Python site package area is a deprecated practice
with recent Python versions. For example, the following command fails on Ubuntu
24.04 with the error message ``error: externally-managed-environment``::

pip install --user pynvim

pip3 install .
Instead, always install into a virtual environment.
28 changes: 28 additions & 0 deletions pynvim/python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Wrapper to expose the Python interpreter as `pynvim-python`.
`setup.py` declares an entry point for the `main()` function below. When
`pynvim` is installed, an executable named `pynvim-python` will be generated
that will invoke `main()` below; that function then simply chains to the
underlying Python interpreter, passing along all command-line arguments.
The intent is to have `pynvim-python` be on the `PATH` such that an invocation
such as:
pynvim-python -c 'import pynvim'
is equivalent to explicitly running the correct Python interpreter where
`pynvim` is installed:
/path/to/python -c 'import pynvim'
This allows Neovim to automatically detect the correct Python interpreter for
use with `pynvim`.
"""

import subprocess
import sys


def main() -> None:
"""Chain to Python interpreter, passing all command-line args."""
subprocess.run([sys.executable] + sys.argv[1:])
5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@
setup_requires=setup_requires,
tests_require=tests_require,
extras_require=extras_require,
entry_points={
'console_scripts': [
'pynvim-python=pynvim.python:main',
],
},
)
3 changes: 2 additions & 1 deletion test/test_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ def test_vars(vim: Nvim) -> None:
def test_options(vim: Nvim) -> None:
vim.current.window.options['colorcolumn'] = '4,3'
assert vim.current.window.options['colorcolumn'] == '4,3'
old_global_statusline = vim.options['statusline']
# global-local option
vim.current.window.options['statusline'] = 'window-status'
assert vim.current.window.options['statusline'] == 'window-status'
assert vim.options['statusline'] == ''
assert vim.options['statusline'] == old_global_statusline

with pytest.raises(KeyError) as excinfo:
vim.current.window.options['doesnotexist']
Expand Down
Loading