Unable to configure `basedpyright`
VictorCMiraldo opened this issue ยท 8 comments
The Problem
I was trying to send some options to basedpyright
from eglot but some options don't seem to be respected. The basedpyright.typeCheckingMode
works, but basedpyright.analysis.diagnosticSeverityOverrides
doesn't, for example.
Said settings do work in lsp-mode
with https://github.com/emacs-lsp/lsp-pyright
Based on the server's config description (link), I'd like to send { "basedpyright": { "analysis": { "diagnosticSeverityOverrides": { "reportUnusedCallResult": "none" }}}}
, for example, and see the following python file indeed not displaying the warning on line 5:
def even(n: int) -> bool:
return n % 2 == 0
if __name__ == "__main__":
even(12)
x = even(11)
print(f"{x}")
MRE
init.el for eglot
(require 'use-package)
(package-initialize)
(use-package eglot
:ensure t
:config
(add-to-list 'eglot-server-programs '(
(python-mode python-ts-mode)
"basedpyright-langserver" "--stdio"
))
(setq-default eglot-workspace-configuration
'(:basedpyright (
;; Changing this to "off" works, so eglot is communicating something!
:typeCheckingMode "recommended"
;; The rest of the settings are not respected though :(
:analysis (
:diagnosticSeverityOverrides (
:reportUnusedCallResult "none"
)
:inlayHints (
:callArgumentNames :json-false
:functionReturnTypes :json-false
:variableTypes :json-false
:genericTypes :json-false
)
)
)
)
)
)
init.el for lsp-mode (this works)
(require 'use-package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(use-package f
:ensure t)
(use-package lsp-mode
:ensure t)
(use-package lsp-ui
:ensure t)
(use-package lsp-pyright
:vc (:url "https://github.com/emacs-lsp/lsp-pyright")
:custom
(lsp-pyright-langserver-command "basedpyright") ;; or basedpyright
(lsp-pyright-diagnostic-severity-overrides '(("reportUnusedCallResult" . "none")))
(lsp-pyright-type-checking-mode "all")
:hook (python-mode . (lambda ()
(require 'lsp-pyright)
(lsp)))) ; or lsp-deferred
I saved both the EGLOT buffer and the lsp-workspace-show-log
buffer in the hopes of comparing both and attempting to understand whether I've done something wrong but I fail to see any reason why basedpyright
obeys lsp-mode but not eglot.
What's especially suspect is that the typeCheckingMode
setting is obeyed on eglot
. Am I sending the other settings in the wrong manner? I also tried using the :initializationOptions
when adding basedpyright
to eglot-server-programs
but no success either.
- eglot interaction log on loading
basedpyright
, with the respectiveinit.el
, on the test file above: eglot-interaction.log - resp. lsp-mode interaction log: lsp-interaction.log
Thank you!
This is what Eglot sent the server based on your configuration.
{
"jsonrpc": "2.0",
"method": "workspace/didChangeConfiguration",
"params": {
"settings": {
"basedpyright": {
"typeCheckingMode": "recommended",
"analysis": {
"diagnosticSeverityOverrides": {
"reportUnusedCallResult": "none"
},
"inlayHints": {
"callArgumentNames": false,
"functionReturnTypes": false,
"variableTypes": false,
"genericTypes": false
}
}
}
}
}
}
Then basedpyright
asks three times for configuration (why?, idk...) it asks
[jsonrpc] e[14:40:58.932] <-- workspace/configuration[1] {"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/victor/test-proj","section":"python"}]}}
To which Eglot replies with [null]
, because there is no python
section the configuration. Then asks
[jsonrpc] e[14:40:58.950] <-- workspace/configuration[2] {"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/victor/test-proj","section":"basedpyright.analysis"}]}}
To which Eglot replies with [null
, because there is no basedpyright.analysis
section the configuration. Then asks
[jsonrpc] e[14:40:58.958] <-- workspace/configuration[3] {"jsonrpc":"2.0","id":3,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/victor/test-proj","section":"basedpyright"}]}}
To which Eglot replies with:
{
"jsonrpc": "2.0",
"id": 3,
"result": [
{
"typeCheckingMode": "recommended",
"analysis": {
"diagnosticSeverityOverrides": {
"reportUnusedCallResult": "none"
},
"inlayHints": {
"callArgumentNames": false,
"functionReturnTypes": false,
"variableTypes": false,
"genericTypes": false
}
}
}
]
}
Because there is indeed a basedpyright
section in the configuration. In fact, Eglot had already communicated it to the server, but maybe it forgot or is hard of hearing or something. Lsp mode replies witht he same large section to all three requests. Maybe basepyright needs to hear the same thing four times to be able to use it.
To which Eglot replies with [null, because there is no basedpyright.analysis section the configuration.
This bit is probably the culprit .
There could be a basedpyright.analysis
section in the configuraiton depending on how you interpret the string basedpyright.analysis
, which could be "the subsection analysis
within the top-level section basedpyright
". However the dotted syntax is not specified in https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration and Eglot does not support it.
Maybe something like this is what you should be using:
(setq-default
eglot-workspace-configuration
'(:basedpyright
#1=(:typeCheckingMode
"recommended"
:analysis
#2=(:diagnosticSeverityOverrides
(:reportUnusedCallResult "none")
:inlayHints
(:callArgumentNames :json-false
:functionReturnTypes :json-false
:variableTypes :json-false
:genericTypes :json-false)))
:basedpyright.analysis #2#
:python #1#))
Amazing! That does work indeed! It would never have occurred to me that the dot had to be part of the name of a section. I think basedpyright
could certainly improve here. It should have listened to the first config sent! I'll summarize your analysis on the basedpyright
issue I made.
Thank you so much for the pedagogical analysis, I learned what to look for and how to interpret some of those messages. (And thank you for Eglot, it's great!)
Glad I could help
hi i'm the maintainer of basedpyright. thanks for looking into this. if i'm understanding this correctly, you're saying the issue is that the config is being sent by the client in the following structure:
{
"basedpyright": {
"analysis": {
"diagnosticSeverityOverrides": {
"reportUnusedCallResult": "none"
}
}
}
}
but the server is expecting it to be:
{
"basedpyright.analysis": {
"diagnosticSeverityOverrides": {
"reportUnusedCallResult": "none"
}
}
}
forgive my ignorance, i had no experience working with language servers until i started working on basedpyright, and there have been many issues with pyright's language server that i've had to fix because it was designed with only vscode in mind. vscode settings are defined like this btw, so i assume that's got something to do with it:
that said, i'm confused as to why this issue only seems to have come up in eglot but none of the other supported LSP clients. for example @VictorCMiraldo said lsp-mode
doesn't have this issue (DetachHead/basedpyright#894 (comment)), and i can confirm that nvim-lspconfig
also works with this struc:ture:
{
"neovim/nvim-lspconfig",
opts = {
servers = {
basedpyright = {
settings = {
basedpyright = {
analysis = {
diagnosticSeverityOverrides = {
reportUnusedCallResult = "none",
}
}
},
},
},
},
},
}
not trying to blame eglot, i'm sure it's something wrong on my side, i'm just really confused as to what's going on here. i would try to investigate further but i have no idea how to use emacs and i haven't been able to figure out an easy way to debug the language server outside of the vscode extension.
I think I understand the issue, I left my opinion on the basedpyright
's repository (DetachHead/basedpyright#894 (comment)) since this is not eglot's fault. Eglot is a law-abiding client... It is the law that is a little too open.
hi i'm the maintainer of basedpyright. thanks for looking into this. if i'm understanding this correctly, you're saying the issue is that the config is being sent by the client in the following structure:
No, that's not it. It's similar, but not exactly that.
not trying to blame eglot,
I know, and it wouldn't be a problem if you did ;-)
There are separate things at play here. In no particular order.
-
Perhaps in contrast to other LSP clients, the Eglot LSP client takes the initiative of sending an early
didChangeConfiguration
with the fullsettings
configuration section, as illustrated above. Not all clients do this, but it's legal, and some servers like it and it's enough to prime their configurations.basedpyright
would seem to ignore it (which, as far as I understand, is legal). -
Anyway,
basedpyright
still asks for configuration again, even though Eglot has in practice no more configuration to give it. It asks for three different sections for the same uri:python
,basedpyright.analysis
andbasedpyright
(in this order). Eglot replies with the empty[null]
response to the first two and with a repeat of what it had already sent to the third one. -
I'm guessing that Eglot's
[null]
response to the middle querybasedpyright.analysis
causes the server to think: "oh, when I asked the client specifically foranalysis
withinbasedpyright
it told me it has no analysis preferences at all, let me just use the defaults" -
The interpretation for the dotted syntax
basedpyright.analysis
is fairly typical, but it is not standardized. I guessed that the meaning was that typical one, so I craft an Eglot configuration snippet for the OP here that would give basedpyright what it wants. -
If there's anything to change on Eglot's side, it's to make it understand this dotted thing syntax, but that wouldn't be following the standard, just following other clients, which is a bit iffy. There's always the risk of breaking something somewhere on another server.
-
If there's something to change on Basedpyright's side, it's to make it not overwrite (but rather merge) what has given to it via
didChangeConfiguration
or:initializationOptions
PS: I used Basedpyright from time to time when writing python (with Eglot) Good job making a fork of pyright!