From 67fc88213559cd4fd5c115693ecf0cdb592911eb Mon Sep 17 00:00:00 2001 From: 4rrw Date: Mon, 13 Apr 2026 12:16:59 +0200 Subject: [PATCH 1/3] feat: checking dependencies, and installing with dialogue box --- lua/pyrepl/init.lua | 7 ++-- lua/pyrepl/python.lua | 80 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/lua/pyrepl/init.lua b/lua/pyrepl/init.lua index c0c4ef1..643fc45 100644 --- a/lua/pyrepl/init.lua +++ b/lua/pyrepl/init.lua @@ -9,9 +9,10 @@ local send = require("pyrepl.send") local group = vim.api.nvim_create_augroup("Pyrepl", { clear = true }) ----@param args table|nil -function M.open_repl(args) - core.open_repl(args) +function M.open_repl() + python.ensure_dependencies(function() + core.open_repl() + end) end function M.hide_repl() diff --git a/lua/pyrepl/python.lua b/lua/pyrepl/python.lua index 556c38d..97ee6c3 100644 --- a/lua/pyrepl/python.lua +++ b/lua/pyrepl/python.lua @@ -203,4 +203,84 @@ function M.get_tool_completions(arglead) end, vim.tbl_keys(tools)) end +---Check if required Python packages are importable. +---@return boolean +function M.check_dependencies() + local ok, python_path = pcall(M.get_python_path) + if not ok then + return false + end + + local obj = vim.system( + { python_path, "-c", "import jupyter_console, pynvim" }, + { text = true } + ):wait() + + return obj.code == 0 +end + +---Check dependencies and, if missing, prompt the user to install them. +---Calls callback only after dependencies are confirmed present. +---@param callback fun() +function M.ensure_dependencies(callback) + if M.check_dependencies() then + callback() + return + end + + local ok, python_path = pcall(M.get_python_path) + if not ok then + vim.notify(python_path, vim.log.levels.ERROR) + return + end + + vim.ui.select(vim.tbl_keys(tools), { + prompt = "Pyrepl: dependencies missing. Install with:", + }, function(tool) + if not tool then + return + end + + local packages_string = table.concat(packages, " ") + local cmd_str = tools[tool]:format(python_path) .. " " .. packages_string + + local buf = vim.api.nvim_create_buf(false, true) + local width = math.floor(vim.o.columns * 0.8) + local height = math.floor(vim.o.lines * 0.4) + local win = vim.api.nvim_open_win(buf, true, { + relative = "editor", + width = width, + height = height, + row = math.floor((vim.o.lines - height) / 2), + col = math.floor((vim.o.columns - width) / 2), + style = "minimal", + border = "rounded", + title = " Installing Pyrepl dependencies ", + title_pos = "center", + }) + + vim.api.nvim_buf_call(buf, function() + vim.fn.jobstart({ "/bin/sh", "-c", cmd_str }, { + term = true, + pty = true, + on_exit = function(_, code) + vim.schedule(function() + if vim.api.nvim_win_is_valid(win) then + vim.api.nvim_win_close(win, true) + end + if code == 0 then + callback() + else + vim.notify( + config.get_message_prefix() .. "installation failed", + vim.log.levels.ERROR + ) + end + end) + end, + }) + end) + end) +end + return M From 73005691c9be30fa5e687b35ace67b8e825d5f7c Mon Sep 17 00:00:00 2001 From: 4rrw Date: Wed, 22 Apr 2026 14:15:26 +0200 Subject: [PATCH 2/3] feat: changed auto_install to non default behaviour, added config option - removed popup window in favor of vim.system() call - no package manager dialog box, defined in config --- lua/pyrepl/config.lua | 1 + lua/pyrepl/python.lua | 77 +++++++++++++++++-------------------------- lua/pyrepl/types.lua | 2 ++ 3 files changed, 33 insertions(+), 47 deletions(-) diff --git a/lua/pyrepl/config.lua b/lua/pyrepl/config.lua index 95b9913..821535b 100644 --- a/lua/pyrepl/config.lua +++ b/lua/pyrepl/config.lua @@ -14,6 +14,7 @@ local defaults = { python_path = "python", preferred_kernel = "python3", jupytext_hook = true, + auto_install = false, } local image_provider_cache diff --git a/lua/pyrepl/python.lua b/lua/pyrepl/python.lua index 97ee6c3..a6c8198 100644 --- a/lua/pyrepl/python.lua +++ b/lua/pyrepl/python.lua @@ -219,7 +219,7 @@ function M.check_dependencies() return obj.code == 0 end ----Check dependencies and, if missing, prompt the user to install them. +---Check dependencies and, if `auto_install` is set, install them silently. ---Calls callback only after dependencies are confirmed present. ---@param callback fun() function M.ensure_dependencies(callback) @@ -228,59 +228,42 @@ function M.ensure_dependencies(callback) return end + local tool = config.get_state().auto_install + if not tool or not tools[tool] then + vim.notify( + config.get_message_prefix() + .. "dependencies missing, run `:PyreplInstall pip|uv` or set `auto_install`", + vim.log.levels.ERROR + ) + return + end + local ok, python_path = pcall(M.get_python_path) if not ok then vim.notify(python_path, vim.log.levels.ERROR) return end - vim.ui.select(vim.tbl_keys(tools), { - prompt = "Pyrepl: dependencies missing. Install with:", - }, function(tool) - if not tool then - return - end - - local packages_string = table.concat(packages, " ") - local cmd_str = tools[tool]:format(python_path) .. " " .. packages_string - - local buf = vim.api.nvim_create_buf(false, true) - local width = math.floor(vim.o.columns * 0.8) - local height = math.floor(vim.o.lines * 0.4) - local win = vim.api.nvim_open_win(buf, true, { - relative = "editor", - width = width, - height = height, - row = math.floor((vim.o.lines - height) / 2), - col = math.floor((vim.o.columns - width) / 2), - style = "minimal", - border = "rounded", - title = " Installing Pyrepl dependencies ", - title_pos = "center", - }) - - vim.api.nvim_buf_call(buf, function() - vim.fn.jobstart({ "/bin/sh", "-c", cmd_str }, { - term = true, - pty = true, - on_exit = function(_, code) - vim.schedule(function() - if vim.api.nvim_win_is_valid(win) then - vim.api.nvim_win_close(win, true) - end - if code == 0 then - callback() - else - vim.notify( - config.get_message_prefix() .. "installation failed", - vim.log.levels.ERROR - ) - end - end) - end, - }) + local packages_string = table.concat(packages, " ") + local cmd_str = tools[tool]:format(python_path) .. " " .. packages_string + + vim.notify(config.get_message_prefix() .. "installing dependencies...") + + vim.system( + { "/bin/sh", "-c", cmd_str }, + { text = true }, + vim.schedule_wrap(function(obj) + if obj.code == 0 then + vim.notify(config.get_message_prefix() .. "dependencies installed") + callback() + else + vim.notify( + config.get_message_prefix() .. "installation failed\n" .. (obj.stderr or ""), + vim.log.levels.ERROR + ) + end end) - end) + ) end return M diff --git a/lua/pyrepl/types.lua b/lua/pyrepl/types.lua index 47b6fa5..e856d80 100644 --- a/lua/pyrepl/types.lua +++ b/lua/pyrepl/types.lua @@ -14,6 +14,7 @@ ---@field python_path string|nil ---@field preferred_kernel string|nil ---@field jupytext_hook boolean +---@field auto_install false | "pip" | "uv" ---Plugin setup opts (all arguments are optional). ---@class pyrepl.ConfigOpts @@ -29,6 +30,7 @@ ---@field python_path? string ---@field preferred_kernel? string ---@field jupytext_hook? boolean +---@field auto_install? false | "pip" | "uv" ---Image provider interface. ---@class pyrepl.Image From d204c30d35d5a8ecfdda18d8070f7cf6ea1ff0b3 Mon Sep 17 00:00:00 2001 From: 4rrw Date: Wed, 22 Apr 2026 14:15:36 +0200 Subject: [PATCH 3/3] doc: docs for autoinstall --- README.md | 10 ++++++++++ doc/pyrepl.txt | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 5aa1658..23fc4d8 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,9 @@ pyrepl.setup({ preferred_kernel = "python3", -- automatically prompt to convert notebook files into python scripts jupytext_hook = true, + -- auto-install missing runtime packages on `:PyreplOpen` + -- set to "pip" or "uv" to enable; false to disable + auto_install = false, }) -- repl ui-related commands @@ -86,6 +89,13 @@ Then install REPL runtime packages with `uv` or `pip` directly from Neovim: :PyreplInstall uv ``` +Alternatively, enable `auto_install` to have pyrepl silently install missing packages +on `:PyreplOpen`: + +```lua +require("pyrepl").setup({ auto_install = "uv" }) -- or "pip" +``` + To use jupytext integration, make sure jupytext is available in Neovim: ```bash diff --git a/doc/pyrepl.txt b/doc/pyrepl.txt index 1e71c6c..2a4236b 100644 --- a/doc/pyrepl.txt +++ b/doc/pyrepl.txt @@ -62,6 +62,9 @@ Minimal `vim.pack` setup with the default config and example keymaps: preferred_kernel = "python3", -- automatically prompt to convert notebook files into python scripts jupytext_hook = true, + -- auto-install missing runtime packages on `:PyreplOpen` + -- set to "pip" or "uv" to enable; false to disable + auto_install = false, }) -- repl ui-related commands @@ -238,6 +241,7 @@ Default configuration: python_path = "python", preferred_kernel = "python3", jupytext_hook = true, + auto_install = false, }) < @@ -293,6 +297,9 @@ Options: Default: "python3". jupytext_hook (boolean) Enable jupytext hook to automatically convert notebook buffers to `py:percent`. Default: true. + auto_install (false | "pip" | "uv") + When |PyreplOpen| is invoked and required runtime packages are + missing, install them using the specified tool. Default: false. ============================================================================== TIPS & TRICKS *pyrepl-tips*