Pymple adds missing common Python IDE features for Neovim when dealing with imports:
- 🦀 automatic import updates on module/package rename
- 🦀 code-action-like import resolution
🪄 Automatic import updates on file/dir move/rename with support for:
neo-tree
(https://github.com/nvim-neo-tree/neo-tree.nvim)nvim-tree
(https://github.com/nvim-tree/nvim-tree.lua)oil.nvim
(https://github.com/stevearc/oil.nvim)yazi.nvim
(https://github.com/mikavilpas/yazi.nvim)mini.nvim
(https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-files.md)
update_python_imports.mp4
pymple_oil.nvim.mp4
return {
{
"alexpasmantier/pymple.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
-- optional (nicer ui)
"stevearc/dressing.nvim",
"nvim-tree/nvim-web-devicons",
},
build = ":PympleBuild",
config = function()
require("pymple").setup()
end,
},
}
use {
"alexpasmantier/pymple.nvim",
requires = {
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
-- optional (nicer ui)
"stevearc/dressing.nvim",
"nvim-tree/nvim-web-devicons",
},
run = ":PympleBuild",
config = function()
require("pymple").setup()
end,
}
The following features are currently available:
- Automatic refactoring of workspace imports on python file/dir move/rename.
- ✅ confirmation prompt
- ✅ preview window
- ✅ optionally ignore individual changes
- currently supports:
- ✅
neo-tree
- ✅
nvim-tree
- ✅
oil.nvim
- ✅
yazi.nvim
- ✅
mini.files
- ✅
- Automatic missing import resolution for symbol under cursor:
- ✅ searches in current workspace
- ✅ searches in virtual environments
- ✅ searches in the python stdlib
- ✅ Automatic project root discovery for python projects
- ✅ Automatic virtual environment discovery
If you're using a file explorer such as neo-tree
, nvim-tree
, oil.nvim
, yazi.nvim
or mini.files
, pymple will automatically detect it and setup the appropriate hooks.
When you rename or move a file or directory, you'll be prompted with a confirmation window and be able to preview the pending changes while discarding the ones you don't want.
While inside the preview window, the current mappings are defined by default:
keybinding | action |
---|---|
<CR> |
Confirm and update the imports |
<C-k> |
Move to the previous change |
<C-j> |
Move to the next change |
<C-i> or dd |
Discard change |
<C-c> or q |
Cancel refactoring and close the window |
update_python_imports.mp4
If you're not using a file explorer, the current alternative would be to manually call :PympleUpdateImports <source> <destination>
after the file rename operation which will bring up the confirmation window mentioned above.
When running LazyVim, you may need to forward Neo‑tree’s rename events to pymple so that automatic import updates kick in.
Drop the snippet below into your lazy.nvim
spec (e.g. plugins/neo-tree.lua
):
{
"nvim-neo-tree/neo-tree.nvim",
opts = function(_, opts)
local api = require("pymple.api")
local config = require("pymple.config")
local function on_move(args)
api.update_imports(
args.source,
args.destination,
config.user_config.update_imports
)
end
local events = require("neo-tree.events")
opts.event_handlers = opts.event_handlers or {}
vim.list_extend(opts.event_handlers, {
{ event = events.FILE_MOVED, handler = on_move },
{ event = events.FILE_RENAMED, handler = on_move },
})
end,
},
By default, pymple will setup a keymap for this (<leader>li
) which you can change in the configuration:
-- automatically register the following keymaps on plugin setup
keymaps = {
-- Resolves import for symbol under cursor.
-- This will automatically find and add the corresponding import to
-- the top of the file (below any existing doctsring)
resolve_import_under_cursor = {
desc = "Resolve import under cursor",
keys = "<leader>li" -- feel free to change this to whatever you like
}
},
When inside a python buffer, with the cursor on any importable symbol, pressing the above keymap will perform the following action:
- if the symbol resolves to a unique import candidate: add that import to the top of the file (after eventual docstrings) and automatically save the file to run any import sorting/formatting autocommands;
- if there are multiple candidates: prompt the user to select the right one and perform step above;
- if there are no candidates matching the symbol: Print a warning message to notify the user.
resolve_import_ini.mov
Here is the default configuration:
default_config = {
{
-- options for the update imports feature
update_imports = {
-- the filetypes on which to run the update imports command
-- NOTE: this should at least include "python" for the plugin to
-- actually do anything useful
filetypes = { "python", "markdown" }
},
-- options for the add import for symbol under cursor feature
add_import_to_buf = {
-- whether to autosave the buffer after adding the import (which will
-- automatically format/sort the imports if you have on-save autocommands)
autosave = true
},
-- automatically register the following keymaps on plugin setup
keymaps = {
-- Resolves import for symbol under cursor.
-- This will automatically find and add the corresponding import to
-- the top of the file (below any existing doctsring)
resolve_import_under_cursor = {
desc = "Resolve import under cursor",
keys = "<leader>li" -- feel free to change this to whatever you like
}
},
-- logging options
logging = {
-- whether to log to the neovim console (only use this for debugging
-- as it might quickly ruin your neovim experience)
console = {
enabled = false
},
-- whether or not to log to a file (default location is nvim's
-- stdpath("data")/pymple.vlog which will typically be at
-- `~/.local/share/nvim/pymple.vlog` on unix systems)
file = {
enabled = true,
-- the maximum number of lines to keep in the log file (pymple will
-- automatically manage this for you so you don't have to worry about
-- the log file getting too big)
max_lines = 1000,
path = "/Users/alex/.local/share/nvim/pymple.vlog"
},
-- the log level to use
-- (one of "trace", "debug", "info", "warn", "error", "fatal")
level = "info"
},
-- python options
python = {
-- the names of root markers to look out for when discovering a project
root_markers = { "pyproject.toml", "setup.py", ".git", "manage.py" },
-- the names of virtual environment folders to look out for when
-- discovering a project
virtual_env_names = { ".venv" }
}
}
If something's not working as expected, start by running checkhealth
inside of neovim to check all your requirements are setup correctly:
:checkhealth pymple

The helpfiles might be of help too:
:help pymple.txt

If that doesn't help, try activating logging and checking the logs for any errors:
require("pymple").setup({
logging = {
file = {
enabled = true,
path = vim.fn.stdpath("data") .. "/pymple.vlog",
max_lines = 1000, -- feel free to increase this number
},
-- this might help in some scenarios
console = {
enabled = false,
},
level = "debug",
},
})
You can then open a buffer with the associated logs by running the following command:
:PympleLogs
NOTE: if you have trouble filtering through the logs, or if you just like colors, maybe this might interest you.
If that doesn't help, feel free to open an issue.