Pynvim
Pynvim is the official Python client and plugin host for Neovim, enabling Python developers to interact with Neovim instances and write powerful remote plugins. Currently at version 0.6.0, it is actively maintained with regular releases addressing bug fixes, performance improvements, and new features.
Common errors
-
E319: No "python3" provider found. Run ":checkhealth vim.provider" for details.
cause Neovim cannot find a Python 3 interpreter with `pynvim` installed, or `g:python3_host_prog` is incorrectly configured or not set.fix1. Ensure `pynvim` is installed for the Python interpreter Neovim uses (check `:py3 print(sys.executable)` and `:py3 import pynvim`). 2. If using a virtual environment, tell Neovim its path by setting `vim.g.python3_host_prog` in your Neovim config (e.g., `init.lua` or `init.vim`): `let g:python3_host_prog = '/path/to/your/venv/bin/python'` (Vimscript) `vim.g.python3_host_prog = '/path/to/your/venv/bin/python'` (Lua) 3. Run `:checkhealth` in Neovim to diagnose further. -
EOFError: Read beyond end of file
cause The connection to the Neovim instance was unexpectedly closed or interrupted, often because the Neovim process itself crashed, was killed, or backgrounded in a way that severed the communication pipe/socket.fixThis often indicates an issue within Neovim or a plugin. 0.6.0 improves handling, but the root cause might be external. Check Neovim's logs (if enabled, e.g., `NVIM_PYTHON_LOG_FILE=logfile nvim`), review your Neovim configuration and plugins for instability, and ensure the Neovim process remains active during `pynvim` interaction. If connecting via `socket`, verify the socket file `/tmp/nvim.sock` exists and Neovim is listening. -
RuntimeError: asyncio.run() cannot be called from a running event loop
cause Attempting to call `asyncio.run()` from within an already active asyncio event loop. This commonly occurs when `pynvim` is hosting a plugin, which already operates within an asyncio event loop.fixInstead of `asyncio.run()`, use `await` directly for awaitable objects if you are within an `async` function managed by the event loop. If you need to run a task concurrently without blocking, schedule it using `asyncio.create_task()` or `nvim.async_call()`.
Warnings
- breaking Pynvim 0.5.0 raised the minimum supported Python version to 3.7. While 0.6.0 still supports 3.7, it is recommended to use Python 3.9+ for optimal compatibility, especially when using modern installation tools like `uv` or `pipx`.
- breaking The `asyncio.get_child_watcher()` function was removed in Python 3.14. Older versions of pynvim (prior to 0.6.0) that relied on this function will cause `AttributeError` or similar failures when run with Python 3.14.
- deprecated The Python package was renamed from `neovim` to `pynvim` in version 0.3.1. While `import neovim` remains an alias for backward compatibility, new projects and updated codebases should use `import pynvim` to avoid confusion and ensure future compatibility.
- gotcha When accessing Vimscript dictionaries (e.g., `nvim.vars['my_dict']`) from Python, pynvim returns a *copy* of the dictionary, not a live reference. Modifying fields directly on the Python object will not persist changes back to Neovim.
- gotcha In remote plugins, synchronous API calls (`sync=True` in decorators) made from within asynchronous handlers can cause Neovim to hang or deadlock, as Neovim waits for the handler to complete while the handler is waiting for Neovim.
Install
-
pip install pynvim -
uv tool install --upgrade pynvim -
pipx install pynvim
Imports
- attach
from pynvim import attach
- neovim (old package name)
import neovim
from pynvim import attach
Quickstart
# Start Neovim in a terminal with: nvim --listen /tmp/nvim.sock
import os
from pynvim import attach
# Connect to a running Neovim instance via socket
# Ensure Neovim is running with `--listen /tmp/nvim.sock`
# For local testing, you might use os.environ.get('NVIM_LISTEN_ADDRESS')
try:
nvim = attach('socket', path=os.environ.get('NVIM_LISTEN_ADDRESS', '/tmp/nvim.sock'))
# Execute a Neovim command
nvim.command('echo "Hello from pynvim!"')
# Get and print the current buffer content
current_buffer = nvim.current.buffer
print(f"First line of current buffer: {current_buffer[0]}")
# Set a Neovim variable
nvim.vars['pynvim_test_var'] = 'Python was here'
print(f"Neovim variable 'pynvim_test_var': {nvim.eval('g:pynvim_test_var')}")
except Exception as e:
print(f"Could not connect to Neovim or encountered an error: {e}")
print("Make sure Neovim is running with '--listen /tmp/nvim.sock' or NVIM_LISTEN_ADDRESS is set.")