Docs: Setup Pyrefly with Neovim
Nice project, wanted to add some information on setting up Pyrefly with Neovim 0.11+ or lspconfig.
lspconfig
local lspconfig = require("lspconfig")
local configs = require("lspconfig.configs")
if not configs.pyrefly then
configs.pyrefly = {
cmd = { "uv", "run", "pyrefly", "lsp" },
filetypes = { "python" },
root_dir = function(fname)
return lspconfig.util.find_git_ancestor(fname) or vim.loop.os_homedir()
end,
settings = {},
},
}
end
lspconfig.pyrefly.setup({})
For Neovim 0.11+
Place lua file under ~/.config/nvim/lsp/, for simplicity sake let's name it pyrefly.lua
return {
cmd = { "pyrefly", "lsp" },
filetypes = { "python" },
settings = {},
on_exit = function(code, _, _)
vim.notify("Closing Pyrefly LSP exited with code: " .. code, vim.log.levels.INFO)
end,
}
then enable it in init.lua
vim.lsp.enable({"pyrefly"})
Hey @akmalsoliev, thanks so much for creating this! I'm a Neovim user myself, but haven't had the time to put anything together for it yet. This is going to be super helpful, and at some point, once our docs are ready, it would be awesome if we can add this in.
At the moment, we're still figuring out how we want to do docs, but someone will reach out or pull this in once we're ready.
Hey @akmalsoliev, thanks so much for creating this! I'm a Neovim user myself, but haven't had the time to put anything together for it yet. This is going to be super helpful, and at some point, once our docs are ready, it would be awesome if we can add this in.
At the moment, we're still figuring out how we want to do docs, but someone will reach out or pull this in once we're ready.
Hey @connernilsen, thank you for the kind words and happy to hear that there a fellow neovim user. v0.11 is super easy and super nice addition, highly recommended. I'm currently working on modifying my config to solve the absurd setup of lsp and other services, I'd also recommend to add Pyrefly to https://github.com/williamboman/mason.nvim registry.
Hi @akmalsoliev! Thank you for sharing your configuration.
I'm using Pyrefly configured with the new LSP API introduced in v0.11, and I've been running into some issues.
It seems that the Pyrefly server doesn't recognize when the client detaches, so after I close Neovim, pyrefly lsp process just keeps running forever. I hadn't noticed it until recently, when I opened htop and saw about 30 pyrefly processes.
I was wondering whether you have encountered the same issue, or it could specific to my setup?
Hi @akmalsoliev! Thank you for sharing your configuration.
I'm using Pyrefly configured with the new LSP API introduced in v0.11, and I've been running into some issues.
It seems that the Pyrefly server doesn't recognize when the client detaches, so after I close Neovim,
pyrefly lspprocess just keeps running forever. I hadn't noticed it until recently, when I openedhtopand saw about 30pyreflyprocesses.I was wondering whether you have encountered the same issue, or it could specific to my setup?
hey @mrsobakin, nice catch, this should fix it:
return {
cmd = { "uv", "run", "pyrefly", "lsp" },
filetypes = { "python" },
settings = {},
on_exit = function(code, _, _)
vim.notify("Closing Pyrefly LSP exited with code: " .. code, vim.log.levels.INFO)
end,
}
Updating my first post
Weird, it doesn't fix the problem for me. It doesn't seem like it's a timing issue -- even when I stop the server manually with :LspStop, the process still hangs indefinitely.
Weird, it doesn't fix the problem for me. It doesn't seem like it's a timing issue -- even when I stop the server manually with
:LspStop, the process still hangs indefinitely.
very weird, are you on the latest version of pyrefly and uv? either way, try adding a:
flags = {
exit_timeout = 5000,
},
under
return {
cmd = { "uv", "run", "pyrefly", "lsp" },
filetypes = { "python" },
settings = {},
on_exit = function(code, _, _)
vim.notify("Closing Pyrefly LSP exited with code: " .. code, vim.log.levels.INFO)
end,
flags = {
exit_timeout = 5000,
},
}
worst case you can just execute a force kill switch on exit, but let me know if exit_timeout helps.
Unfortunately I had no luck with exit_timeout.
I'm running the latest versions of pyrefly and uv that are available on pypi:
$ pip list | grep '\(pyrefly\|uv\) '
pyrefly 0.14.1
uv 0.7.3
$ nvim -v
NVIM v0.11.1
Build type: RelWithDebInfo
LuaJIT 2.1.1741730670
Run "nvim -V1 -v" for more info
In :LspInfo, I can verify that all arguments are indeed recognized by Neovim:
- pyrefly:
- cmd: { "uv", "run", "pyrefly", "lsp" }
- filetypes: python
- flags: {
exit_timeout = 5000
}
- on_exit: <function @/home/sbkn/.config/nvim/lsp/pyrefly.lua:5>
- settings: {}
What's even more strange is that even after :LspStop, pyrefly is still reported as active:
vim.lsp: Active Clients ~
- pyrefly (id: 1)
- Version: ? (no serverInfo.version response)
- Root directory: nil
- Command: { "uv", "run", "pyrefly", "lsp" }
- Settings: {}
- Attached buffers: 1
lsp.log also doesn't seem to contain any useful information (15:11:09 is the startup time):
[ERROR][2025-05-10 15:11:09] ...p/_transport.lua:36 "rpc" "uv" "stderr" "starting generic LSP server\n"
[ERROR][2025-05-10 15:11:09] ...p/_transport.lua:36 "rpc" "uv" "stderr" "Reading messages\n"
[ERROR][2025-05-10 15:11:09] ...p/_transport.lua:36 "rpc" "uv" "stderr" "Workspaces emtpy, skipping project file population\n"
Even though I don't have any plugins/configuration that might interfere with lsp, I deleted my config and created a minimal one just in case:
$ exa --tree ~/.config/nvim
/home/sbkn/.config/nvim
├── init.lua
└── lsp
└── pyrefly.lua
$ cat init.lua
vim.lsp.config("pyrefly", {})
vim.lsp.enable({"pyrefly"})
$ cat lsp/pyrefly.lua
return {
cmd = { "uv", "run", "pyrefly", "lsp" },
filetypes = { "python" },
settings = {},
on_exit = function(code, _, _)
vim.notify("Closing Pyrefly LSP exited with code: " .. code, vim.log.levels.INFO)
end,
flags = {
exit_timeout = 5000,
},
}
However even with it, the issue still persists.
I suppose that it is possible that my setup is somehow tainted by some other seemingly unrelated program or its configuration. I have an another more-or-less clean install of Arch Linux. I will test it there and report the status a bit later.
I suppose that it is possible that my setup is somehow tainted by some other seemingly unrelated program or its configuration. I have an another more-or-less clean install of Arch Linux. I will test it there and report the status a bit later.
Does not work on it either.
Hey @mrsobakin,
I'm on macOS, hence, some things could differ.
I installed uv via sh, not via pip.
Did you try installing pyrefly via tool? uv tool install pyrefly
if nothing helps then add this command to on exit:
os.execute("pkill -f 'pyrefly lsp'")
Thank you so much for your time @akmalsoliev.
Unfortunately installing and running pyrefly via uv tool doesn't seem to yield any results or new information. I don't think that uv is at fault here, since the issue persists regardless of whether I use it or not. I could hack a solution with pkill, but at this point I'm interested in finding a root cause of this issue.
From what I can tell, it's not caused by the Neovim either: I enabled debug logs with vim.lsp.set_log_level("debug") and ran it with both pyrefly and rust-analyzer.
Neovim sends the exact same messages to both servers. Moreover, it looks like they both reply to the "shutdown" message. Could it be that pyrefly just ignores the exit event?
As of now, I have two theories: either exit event is (for some reason) ignored completely, or there is a thread lock somewhere. I've skimmed through the pyrefly LSP code, and the second option seems more likely.
It turns out that there indeed was a deadlock. It should be fixed after #185 is merged.
@akmalsoliev, good point on the Mason registry. I'll take a look on adding it there after PyCon!
Just want to update here, I have PRs open for neovim/nvim-lspconfig and mason-org/mason-registry right now, we're just waiting on approval (it seems like Mason is ready to go once lspconfig is done).
You can track it here: https://github.com/facebook/pyrefly/issues/227
A nice little trick is just installing Pyrefly globally with uv:
uv tool install pyrefly
If you're using some dashboard then you can upgrade it adding this command:
vim.fn.system("uv tool upgrade --all")
A nice little trick is just installing Pyrefly globally with uv:
uv tool install pyrefly
Ooh good to know, I'll add that into our docs once we're merged into the lspconfig registry.
If you're using some dashboard then you can upgrade it adding this command:
vim.fn.system("uv tool upgrade --all")
Is a dashboard a plugin or something? I'm not sure I know what you're talking about here. Auto upgrading sounds super useful to have though!
Is a dashboard a plugin or something? I'm not sure I know what you're talking about here. Auto upgrading sounds super useful to have though! Yes, it is a welcome/home page when you enter neovim. Examples:
- https://github.com/nvimdev/dashboard-nvim
- https://github.com/folke/snacks.nvim/blob/main/docs/dashboard.md
i believe this should be a pirority to docs it well in the future
We actually weren't dealing with the exit notification. I've put up a patch to deal with this in #365
Alright, it took a while, but I was finally able to finish up writing the documentation for setting up Pyrefly in Neovim, as well as getting Pyrefly configs into mason-org/mason-repository and neovim/nvim-lspconfig. I'm sure there are improvements we can make, but these should be good enough to start with for now.
Thank you everyone for your participation!
I'm going to close this issue since we now have the documentation up. If there are improvements anyone thinks we should make, feel free to open a new issue addressing the specific problem or make a PR if you're open to contributing!
@connernilsen are you open to doc contributions?
@akmalsoliev - yep, we very much appreciate all contributions, including doc contributions. See https://github.com/facebook/pyrefly/blob/main/CONTRIBUTING.md for notes on contributing.
Sorry for not seeing this message sooner! I suspect the fact it was on a closed issue meant no one was scanning.