-
-
Save doolio/8c1768ebf33c483e6d26e5205896217f to your computer and use it in GitHub Desktop.
;;; Directory Local Variables | |
;;; For more information see (info "(emacs) Directory Variables") | |
;;; Commentary: | |
;; .dir-locals.el for use with the Emacs Eglot LSP client and | |
;; python-lsp-server (pylsp) LSP server v1.10.0. | |
;; Default values in accordance with | |
;; https://github.com/python-lsp/python-lsp-server/blob/v1.10.0/CONFIGURATION.md | |
;; (or commit 2a5a953). A value of null means we do not set a value and | |
;; therefore use the plugin's default value. | |
;; The recommended format for the `eglot-workspace-configuration' variable | |
;; value is a property list (plist for short): | |
;; | |
;; (:server plist…) | |
;; | |
;; Here :server identifies a particular language server and plist is the | |
;; corresponding keyword-value property list of one or more parameter | |
;; settings for that server, serialized by Eglot as a JSON object. | |
;; plist may be arbitrarily complex, generally containing other | |
;; keyword-value property sublists corresponding to JSON subobjects. | |
;; The JSON values are represented by Emacs Lisp values as follows: | |
;; JSON | Emacs Lisp | |
;; ------------------------------------------------ | |
;; :true i.e. true | t | |
;; :false i.e. false | :json-false | |
;; :null i.e. null | nil | |
;; :[] i.e. [] the empty array | []* | |
;; :{} i.e. {} the empty object | eglot-{}** | |
;; * Lisp array elements should not be comma separated as they are in a | |
;; JSON array. | |
;; ** Must be evaluated via a backquote or `list' | |
;; e.g. `(:pylsp (:plugins (:jedi (:env_vars ,eglot-{})))) or | |
;; (list :pylsp (list :plugins (list :jedi (list :env_vars eglot-{})))) | |
;;; How to Use: | |
;; 1. Place this file in your project directory. | |
;; 2. Adjust settings as desired. Inline comments below indicate the | |
;; expected type, possible values if appropriate and default pylsp value | |
;; for each configuration setting. | |
;;; Code: | |
((python-mode | |
. ((eglot-workspace-configuration | |
. (:pylsp (:configurationSources ["pycodestyle"] ; string array: ["flake8"] or ["pycodestyle"] (default) | |
:plugins (;; Note autopep uses some pycodestyle settings further down to avoid redefining things namely aggressive, exclude, hangClosing, ignore, maxLineLength and select | |
:autopep8 | |
(:enabled t) ; boolean: true (default) or false | |
:flake8 | |
(:config nil ; string: null (default) | |
:enabled :json-false ; boolean: true or false (default) | |
:exclude [] ; string array: [] (default) | |
:executable "flake8" ; string: "flake8" (default) | |
:extendIgnore [] ; string array: [] (default) | |
:filename nil ; string: null (default) | |
:hangClosing nil ; boolean: true or false; null (default) | |
:ignore [] ; string array: [] (default) | |
:indentSize nil ; integer: null (default) | |
:maxComplexity nil ; integer: null (default) | |
:maxLineLength nil ; integer: null (default) | |
:perFileIgnores [] ; string array: [] (default) e.g. ["file_path.py:W305,W304"] | |
:select nil) ; string array: null (default) | |
:jedi | |
(:auto_import_modules ["numpy"] ; string array: ["numpy"] (default) | |
:env_vars nil ; object: null (default) | |
:environment nil ; string: null (default) | |
:extra_paths []) ; string array: [] (default) | |
:jedi_completion | |
(:cache_for ["pandas" "numpy" "tensorflow" "matplotlib"] ; string array: ["pandas", "numpy", "tensorflow", "matplotlib"] (default) | |
:eager :json-false ; boolean: true or false (default) | |
:enabled t ; boolean: true (default) or false | |
:fuzzy :json-false ; boolean: true or false (default) | |
:include_class_objects :json-false ; boolean: true or false (default) | |
:include_function_objects :json-false ; boolean: true or false (default) | |
:include_params t ; boolean: true (default) or false | |
:resolve_at_most 25) ; integer: 25 (default) | |
:jedi_definition | |
(:enabled t ; boolean: true (default) or false | |
:follow_builtin_definitions t ; boolean: true (default) or false | |
:follow_builtin_imports t ; boolean: true (default) or false | |
:follow_imports t) ; boolean: true (default) or false | |
:jedit_hover | |
(:enabled t) ; boolean: true (default) or false | |
:jedi_references | |
(:enabled t) ; boolean: true (default) or false | |
:jedi_signature_help | |
(:enabled t) ; boolean: true (default) or false | |
:jedi_symbols | |
(:all_scopes t ; boolean: true (default) or false | |
:enabled t ; boolean: true (default) or false | |
:include_import_symbols t) ; boolean: true (default) or false | |
:mccabe | |
(:enabled t ; boolean: true (default) or false | |
:threshold 15) ; integer: 15 (default) | |
:preload | |
(:enabled t ; boolean: true (default) or false | |
:modules []) ; string array: [] (default) | |
:pycodestyle | |
(:enabled t ; boolean: true (default) or false | |
:exclude [] ; string array: [] (default) | |
:filename [] ; string array: [] (default) | |
:hangClosing nil ; boolean: true or false; null (default) | |
:ignore [] ; string array: [] (default) | |
:indentSize nil ; integer: null (default) | |
:maxLineLength nil ; integer: null (default) | |
:select nil) ; string array: null (default) | |
:pydocstyle | |
(:addIgnore [] ; string array: [] (default) | |
:addSelect [] ; string array: [] (default) | |
:convention nil ; string: "google", "numpy" or "pep257"; null (default) | |
:enabled :json-false ; boolean: true or false (default) | |
:ignore [] ; string array: [] (default) | |
:match "(?!test_).*\\.py" ; string: "(?!test_).*\\.py" (default) | |
:matchDir "[^\\.].*" ; string: "[^\\.].*" (default) | |
:select nil) ; string array: null (default) | |
:pyflakes | |
(:enabled t) ; boolean: true (default) or false | |
:pylint | |
(:args [] ; string array: [] (default) | |
:enabled :json-false ; boolean: true or false (default) | |
:executable nil) ; string: null (default) | |
:rope_autoimport | |
(:code_actions (:enabled t) ; boolean: true (default) or false | |
:completions (:enabled t) ; boolean: true (default) or false | |
:enabled :json-false ; boolean: true or false (default) | |
:memory :json-false) ; boolean: true or false (default) | |
:rope_completion | |
(:eager :json-false ; boolean: true or false (default) | |
:enabled :json-false) ; boolean: true or false (default) | |
:yapf | |
(:enabled t)) ; boolean: true (default) or false | |
:rope | |
(:extensionModules nil ; string: null (default) | |
:ropeFolder nil))))))) ; string array: null (default) |
An example is provided in the commentary section already but it does not work but it should - see this discussion.
Thanks. Ignoring the fact that it is not working, do you happen to know how could we use the eglot-{}
to write a json object?
Imagine I want to create the json object:
{"VIRTUAL_ENV": "/some/path"}
is it something like:
eglot-{"VIRTUAL_ENV" "/some/path"}
?
This seems to work, even though eglot doesn't like it
(let ((myhash (make-hash-table :size 1)))
(puthash "VIRTUAL_ENV" "/some/path" myhash)
(jsonrpc--json-encode `(:pylsp (:plugins (:jedi (:env_vars ,myhash :environment nil :extra_paths []))))))
My understanding is that eglot-{}
is the Lisp object representation of the empty JSON object i.e. {}
. To set a non-empty JSON object I believe we just continue to add nested plist
s (untested).
(:pylsp (:plugins (:jedi (:env_vars (:VIRTUAL_ENV "/some/path")))))
(From our other discussions elsewhere, perhaps you would be better served by exporting this environment variable via direnv
since you use that too.)
To set a non-empty JSON object I believe we just continue to add nested
plist
s (untested).
You are right. This worked:
((python-mode
. ((eglot-workspace-configuration
. (:pylsp (:configurationSources ["pycodestyle"]
:plugins (:jedi
(:env_vars (:SOME_ENV_VAR "/some/path")
:environment "/env/path" ))))))))
Thanks!
Glad to hear it.
A simple question:
I installed pylsp
with [all]
and enabled auto import with
:rope_autoimport
(:enabled t ; boolean: true or false (default)
:memory :json-false) ; boolean: true or false (default)
If I include
_,ext = os.path.splitext(file)
without import os
in my code, the error is shown, but when i click on os.path it tells me that there are no code actions on the error. I was expecting auto_import to kick in.
I don't use rope
myself but
I installed pylsp with [all]
Perhaps confusingly this does not install rope
. See here. Are you having this issue with rope
installed?
Right, but have you installed rope
into the environment where you installed pylsp
? It is not installed by default with "python-lsp-server[all]". You need to also run:
pip3 install "python-lsp-server[rope]"
For some reason using this file I get the following error:
error in process filter: run-hook-with-args: Wrong type argument: listp, :pylsp
error in process filter: Wrong type argument: listp, :pylsp
and it doesn't seem to be reading my pylsp
config options. However, if I slightly change the syntax it seems to work, like so
((python-mode
. ((eglot-workspace-configuration
. ((:pylsp :configurationSources ["flake8"]
:plugins (:jedi
(:environment "./.venv/"))))))))
Any idea why? (I'm not too familiar with elisp, my main knowledge is from looking at other configs to build my own config)
Any idea why?
There was an option (namely :follow_builtin_definitions
) with a missing value which may have been the cause. I've updated the file to correct this oversight and to further reflect the latest version of the server (v1.7.2). Could you try again to see if that resolved your issue?
As to why your version works I can only assume it is (another) form acceptable to eglot. There was a time eglot accepted many different forms but the one presented here is now the agreed upon form to use. See for example this discussion on this topic.
There was an option (namely
:follow_builtin_definitions
) with a missing value which may have been the cause. I've updated the file to correct this oversight and to further reflect the latest version of the server (v1.7.2). Could you try again to see if that resolved your issue?
Thanks, I still have this issue although I noticed I only have the issue with python-ts-mode
and not with python-mode
(so your snippet works just fine as is now). Probably has something to do with how I set up eglot for python-ts-mode
:
(add-to-list 'eglot-server-programs
`(python-ts-mode . ,(eglot-alternatives
'(("pylsp")
("pyright-langserver" "--stdio")))))
Interesting, I'm still on Emacs 27.1 so haven't tried the new python-ts-mode
yet. So thanks for the heads up. It may be worth opening an issue on the eglot github repository as I'm sure they would be interested to understand why this does not work for the new modes. It's likely other ts-modes are affected also. Eglot already knows about the most popular python language servers such as pylsp and pyright so there should be no need to configure that yourself. You might trying the following to configure Emacs to use the tree-sitter mode when opening a python file and then replace any python-mode-hook
s you may have with python-ts-mode-hook
s. So you could do away with what you have above.
(add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode))
Hey, I'm back again with a question.
I am trying to get rope_autoimport working. I just briefly tried your gist and it worked for like a while, however it suddenly stopped working for me. Everything else is working, it's just that the rope_autoimport is not working. I have rope and python-lsp-server[rope] installed in my venv, and am using the same .dir-locals.el file in your gist.
As far as I can see, I also don't see any mention of "autoimport" in my Eglot events buffers anymore (it used to be there before).
Is it working correctly for you? Do you know how I can debug this in my case?
Is it working correctly for you? Do you know how I can debug this in my case?
I don't use rope
and never have. I presume you have the third party plugin Is other pylsp-rope
installed in the same venv.rope
functionality working as you expect?
am using the same .dir-locals.el file in your gist
In the gist rope-autoimport is not enabled as by default it is disabled in python-lsp
.
:rope_autoimport
(:code_actions (:enabled t) ; boolean: true (default) or false
:completions (:enabled t) ; boolean: true (default) or false
:enabled t ; boolean: true or false (default)
:memory t) ; boolean: true or false (default)
Please confirm your settings are as follows. If not update your settings as above and test again.
Can you give me a minimal example to test if it is working for me?
@doolio sure, please see below:
Virtual environment
Install the following packages in your venv: python-lsp-server[rope] rope
.
.dir-locals.el
I am using your snippet with the following amendments:
:rope_autoimport
(:code_actions (:enabled t) ; boolean: true (default) or false
:completions (:enabled t) ; boolean: true (default) or false
:enabled t ; boolean: true or false (default)
:memory t) ; boolean: true or false (default)
:rope_completion
(:eager :json-false ; boolean: true or false (default)
:enabled t) ; boolean: true or false (default)
I am using python-ts-mode instead of python-mode as well, but I don't think that should matter.
script.py
In an empty file, when you type something like mat
, I would expect it to show a completion menu with the built-in package math
as a suggestion to auto-import. Here is an example with some screenshots.
Yes, it seems to be working for you!
My Eglot events buffer does not mention anything about rope, let alone autoimport. I’m not sure why, as I’m sure the package and plugins are installed.
Copying over my whole events buffer might be oo much, but is there anything else I could do to find out what the issue is with my setup?
OK, so I'm still on Emacs 27.1 so am not using python-ts-mode
. Maybe, that is the reason we are seeing different behaviours? What is your python
and eglot
configurations?
Can you share an example of how to use
eglot-{}
in order to configure Jedi's:env_vars
?