reddit / emacs

Virtual Environments with Eglot, Tramp, and Pyright · robbmann

renzmann · 2022-11-19 23:15
renzmann · 2022-11-19 23:18
This is my first time throwing one of my posts out into the public sphere, so appreciate any and all constructive criticism! For a while now I've been hacking a lot of different attempts at running LSP over Tramp, mostly for data science projects. I finally landed on pyright + eglot, and this post goes over a little elisp snippet I now use to make sure `pyright` launches with the correct Python virtual environment.
mickeyp · 2022-11-20 07:23
Good article! Here's a JSON tip though. Try using `json-encode`: (json-encode '(:foo "bar" :bar "biz")) "{\"foo\":\"bar\",\"bar\":\"biz\"}"
plm314 · 2022-11-20 07:27
This is great. Thanks. I wonder if you could pass this info directly to eglot-workspace-configuration and perhaps keep that variable in a .dir-locals.el instead of writing the config to a file that may interfere with a different person working on the same checkout of the code.
wunderspud7575 · 2022-11-20 09:46
Nicely written article. I've been using spacemacs for a while now and have noticed that the python lsp config that ships with does a reliable job of activating the right venv for projects, including those using Poetry. Might be worth looking at how the python, lsp, and project layers of spacemacs accomplish this. Edit:typo
aaronemassey · 2022-11-20 13:37
So, I absolutely love eglot and it's a daily driver for me. However, for Python I've found a lot more ease using and configuring elpy. It also comes with some extra python specific features like sending the buffer or function to a repl as well as a debugger. *Edit: my understanding is that elpy also worka very well over tramp. Thank you for the post and discussion of your tooling!!!
renzmann · 2022-11-20 13:52
It might have been worth mentioning in the article, but elpy is currently off the table for me just because it's no longer maintained. If the package kicks up maintenance again I'd be willing to give it a shot, though. > sending the buffer or function to a repl I haven't had any trouble with the built-in `python.el` versions of this kind of functionality. My motivation is much more driven by accurate type hinting/checking, which both of `mypy` and `pyright` have done very well for me, and integrate with tooling outside Emacs, such as pre-commit hooks to tell me how bad the code I was about to submit is.
renzmann · 2022-11-20 13:56
They say the best way to get the answer you want is to post a slightly wrong version online and let people correct you. This is fabulous, thanks.
renzmann · 2022-11-20 14:03
I haven't touched any spacemacs since I'm pretty invested in my own hand-rolled stuff. Is it using `lsp-mode` instead of `eglot`? If so, I agree that I had an easier time getting `lsp-mode` to spot project settings. As mentioned in the article, though, it took some extra tinkering to configure a `pyright-remote` client with `lsp-mode` for Tramp, which is more for me to maintain. Also, less relevant to the broader discussion, the specific machines I'm usually working on just get stuck trying to set up the connection between `lsp-mode` and the language server. There's almost certainly a configuration step I'm missing there, but wound up with this version since `eglot` *just worked* instead of requiring a bit of debugging.
renzmann · 2022-11-20 14:07
Darn, in my research dive I hadn't found this variable - I was too focused on the `pyright` documentation itself from GitHub. Thanks for pointing it out, I'll have to give it a try. However, for the remote machines I'm dealing with I do have to leave `.dir-locals` disabled (the default behavior) until I can find whichever configuration stops it from tracing all the way up to the root directory. When working on network mounted drives, that walk up to `/` looking for `.dir-locals` induces a catastrophic amount of slowdown for Tramp.
doolio_ · 2022-11-20 15:46
As a starting point, [here](https://github.com/joaotavora/eglot/discussions/1096) is a `.dir-locals` file for the python-lsp-server (pylsp) for use with eglot. I was planning on creating one for pyright at some point. Do you find the pyright error reporting as good as pylsp? Edit: wrt to finding and configuring the right environment you might consider `direnv` + poetry if you want to manage project dependencies.
renzmann · 2022-11-20 16:08
I much prefer the `pyright` experience to `python-lsp-server`. * I dislike that `pylsp` requires managing many extra python dependencies to get the same functionality - e.g. `pylsp-mypy`. There's also the possibility of installing a stubs version that's out of sync with the package I'm type checking, which is not possible with `pyright`, since it just directly uses the sources in the virtual environment. * I find that the highlighting/errors are better localized with `pyright` on `eglot`, more frequently taking me to the exact symbol with the error, rather than highlighting the whole line * `pyright` has been much snappier for me, with faster updates as I type on somewhat slow remote machines + connections I've also been an ardent `poetry` user for about a year now, and I'd have it no other way. `direnv` does look interesting though and I hadn't run into it, thanks for pointing that out.
doolio_ · 2022-11-20 16:22
Thanks, I'll be sure to give pyright another whirl. I tried it previously but thought it provided too much info via eldoc and did not report some errors reported via pylsp. Yes, it's true pylsp uses many tools under the hood rather than providing the analysis natively. Yes, direnv is great. I've submitted a [PR](https://github.com/direnv/direnv/pull/995) to have poetry support built-in. It's been working well in my direnvrc.
terminal_cope · 2022-11-20 17:39
> wrt to finding and configuring the right environment you might consider `direnv` I use and enjoy direnv, but (IIRC) there is a caveat that by default it gets evaluated too late for `lsp`. So, I had to *not* directly enable `lsp` for `python-mode` and instead add my own hook function that calls `(direnv-update-directory-environment)` and then `(lsp)`. Actually, that's probably a good idea in general for `lsp`, if you use `direnv`, not just for `python-mode`.
doolio_ · 2022-11-20 17:45
Thanks, I'd not encountered this as I typically open a file in my project triggering `direnv` and activating the virtual environment and then `M-x eglot`.
terminal_cope · 2022-11-20 20:21
I typed this and forgot the topic was `eglot`... But it still might apply if you have `eglot` enabled by default in the mode hook. Digging in a little I see `direnv` happens in the `before-hack-local-variables-hook`, meaning if you use `dir-locals` to configure your LSP environment, and enable `eglot`/`lsp` by default, you may need to use an even later hook.
JDRiverRun · 2022-11-20 22:53
You can also set `eglot-workspace-configuration` to a function in recent versions, and avoid the external file. Here's what I use. This uses an unreleased package I call simple-venv, but anything that identifies a containing virtual environment would work. (defun my/eglot-workspace-config (server) (if-let ((venv (simple-venv-find)) ((not (eq venv 'none))) (vp (file-name-directory venv)) (vn (file-name-nondirectory venv))) (list (cons :python (list :venvPath vp :venv vn :pythonPath (simple-venv-interpreter venv)))))) (setq-default eglot-workspace-configuration #'my/eglot-workspace-config)
Extension_Try_6870 · 2022-11-21 06:33
I use direnv with envrc.el. And it seems that by default the env is activated before eglot starts.
doolio_ · 2022-11-21 09:52
That was my experience too when using `eglot-ensure` but now I simply use `M-x eglot` to avoid unnecessary errors if a language server is not installed.
terminal_cope · 2022-11-21 15:25
Interesting - looks like a better solution than `direnv.el` I've been using.
doolio_ · 2022-11-21 21:19
Perhaps, I too use envrc.el.
anton-sug4r · 2022-11-30 20:41
For this to work, does the LSP server need to be installed on the remote machine? I am trying to use Tramp and eglot, and I get the error that pyright command is not found when opening a file on the remote machine.
renzmann · 2022-12-01 13:56
Yes, same as any other external tool that you might use with say, ‘M-x compile’, it must be executable on the machine that has your source.
whompyjaw · 2022-12-08 19:37
Hi Rob, I read the article but still don't have success. I am using Doom EmacsI have the server installed here: `/home/user/.nvm/versions/node/v18.3.0/bin/pyright` And get this error: `Error in post-command-hook (#[0 "\303\304\301\242\305#\210\300\306!\205\0r\211q\210?\205\0\307\310\311 \")\207" [#<buffer 2slot_lvds.py> (#0) eglot--managed-mode remove-hook post-command-hook nil buffer-live-p apply eglot--connect eglot--guess-contact] 4]): (error "None of ’pylsp, pyls, pyright-langserver, jedi-language-server’ are valid executables")[jsonrpc] Server exited with status 1error in process sentinel: eglot--error: [eglot] -1: Server diederror in process sentinel: [eglot] -1: Server died` &#x200B; If you happen to use `pyenv` i also have this issue (i am sharing in case they are related):`pyenv: version ‘venv’ is not installed (set by ‘/ssh:<user>@<hostname>:/local/mnt/workspace/<user>/<project_name>/.python-version’).` &#x200B; I have the \``pyrightconfig.json`\` in the root of my project with:`{"venvPath": "/local/mnt/workspace/<user>/pyenv/versions","venv": "<name_of_env>"}`(**Note:** everything in the angled brackets is the real name. This is work environment) Any thoughts on how to help? I would be greatly appreciative. I have been banging my head against the wall to get this working and I just can't. My "client" is WSL2. edit: Pyright is in my path: >\[user@host project\]$ pyright 1slot\_lvds.py Loading configuration file at /local/mnt/workspace/user/project/pyrightconfig.json Assuming Python version 3.8 Assuming Python platform Linux Auto-excluding \*\*/node\_modules Auto-excluding \*\*/\_\_pycache\_\_ Auto-excluding \*\*/.\* stubPath /local/mnt/workspace/user/project/typings is not a valid directory. Searching for source files Found 1 source file pyright 1.1.266 0 errors, 0 warnings, 0 informations Completed in 1.967sec edit2: I am sorry for terrible formatting, reddit's fancy editor is hot garbage.
renzmann · 2022-12-08 21:03
What's adding `pyright` to your path on the host machine? Tramp uses `sh` by default, so if the answer is `~/.bashrc`, then Tramp won't pick it up. You could try adding a symlink to `pyright` under `~/.local/bin`, then making sure `~/.profile` is adding that folder to PATH: ``` $ ln -s /home/user/.nvm/versions/node/v18.3.0/bin/pyright ~/.local/bin/pyright $ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.profile ``` If you don't want to putz with `~/.profile`, you can also tell Tramp to put things on PATH explicitly: ``` (add-to-list 'tramp-remote-path "~/.local/bin") ;; or just point directly to the folder that has `pyright` in it ```