wyuenho / emacs-pet Goto Github PK
View Code? Open in Web Editor NEWTracks down the correct Python tooling executables from your virtualenvs so you can glue the binaries to Emacs and delete code in init.el
License: GNU General Public License v3.0
Tracks down the correct Python tooling executables from your virtualenvs so you can glue the binaries to Emacs and delete code in init.el
License: GNU General Public License v3.0
Description
I use eglot in a virtual environment. Everything works fine except that mypy does not load the stubs for typechecking imported modules. I'm using flymake, and it reports an error that mypy cannot find the stubs. Except that the stubs are installed in the venv.
If I switch to flycheck, the mypy error goes away. Thus I believe that flymake somehow does not fully recognize the environemt set by PET.
If I can test this, I'd welcome some pointers how to investigate this issue. It might, of course, also be due to eglot, but I have no idea how to test it (and I do not want to install lsp-mode).
** Setup
setq-locale
and the hook python-base-mode-hook
.Description
I use projectile and working with Python code in projects works fine. But when I open a script that is not part of a project, I cannot kill the buffer. Pet adds the function pet-cleanup-watchers-and-caches to the kill-buffer-hook. Within that function pet-project-root returns nil and an error is thrown.
Desktop :
System tools versions
pet-project-root
returns nil
in my sample python project initialized using poetry
. I am using Emacs 28.2 without projectile
.
pet-locate-dominating-file
should generally return the directory which has pyproject.toml
but fails to do so as it is also dependent on pet-project-root
. Removing the dependency on pet-project-root
should help in this case.
Line 157 in 7620c18
Description
If both precommit
and poetry
are installed then pet-executable-find
will attempt to use precommit
to search for binaries and this is most likely not what is wanted. precommit
is used to set up git commit hooks and it is very common to use it with a poetry
or pipenv
project.
The above mentioned behavior will result in a binary (e.g. black
) not being found by pet-executable-find
because it is in the virtual environment created by poetry
and not precommit
- and this despite pet-virtualenv-root
detecting the virtual environment correctly.
Reproduction steps
Expected behavior
pet-executable-find
should not prioritize precommit
over the more common package managers like poetry
or pipenv
.
PET version
1.0.3 (current master)
Emacs version
29.0.50 (self built)
Desktop (please complete the following information):
System tools versions
In https://github.com/wyuenho/emacs-pet/blob/main/pet.el#L221 you're using string-match-p
for the config file extensions.
This doesn't work for me, because string-match-p
returns 0 in my case. I would simply use
(or (equal "yaml" ext)
(equal "yml" ext)
(eq 'yaml-mode mode))
or maybe you have a better idea.
(string-match-p "ya?ml" "yaml")
0
(string-match-p "ya?ml" "yml")
0
Description
There is code in pet.el that tries to find an environment yaml in the project, for which the following regex is used "environment.ya?ml". This regex is passed to
(pet-find-file-from-project "environment.ya?ml")
, which returns nil when I run it inside a conda project. However, if I remove the regex and use "environment.yml" instead, it returns the filename:
~/gitrepos/2022 $ (pet-find-file-from-project-root "environment.ya?ml")
~/gitrepos/2022 $ (pet-find-file-from-project-root "environment.yml")
/home/thomas/gitrepos/2022/environment.yml
Reproduction steps
Expected behavior
~/gitrepos/2022 $ (pet-find-file-from-project-root "environment.ya?ml")
should return the expected file
PET version
pet 20220905.2004
Emacs version
29.0.50
Desktop (please complete the following information):
Description
When I run pet-verify-setup
in e.g. the pytest git repo, the following messages are output in my Messages buffer
mapc: Symbol’s value as variable is void: lsp-jedi-executable-command
In "../../../../.pylintrc":
Unrecognized option found: no-space-check [unrecognized-option]
I have a .pylintrc file in my homedir, which probably is not compatible with the pylint executable that was found by pet-find-executable
.
jedi is probably not installed anywhere, that's why I gest the symbol's value as var is void message (not 100% sure).
Expected behavior
The symbol's value as var is void message is probably an issue with pet.el, which should be fixed.
Not sure if the path in In "../../../../.pylintrc":
is determined by pet.el. If yes, it could be converted to an absolute path before it is output.
The warnings that are output in Messages should be output in the *pet*
buffer instead similar to the way this is done in flycheck-verify-setup
.
Desktop (please complete the following information):
System tools versions
Additional context
Output of M-x (pet-verify-setup)
exec-path: ("/home/thomas/.guix-profile/bin" "/home/thomas/.config/guix/current/bin" "/home/thomas/miniconda/bin" "/home/thomas/miniconda/condabin" "/home/thomas/.cargo/bin" "/snap/bin" "/home/thomas/.cargo/bin" "/home/thomas/.cask/bin" "/opt/emacs-dev/bin" "/home/thomas/bin" "/home/thomas/.fzf/bin" "/home/thomas/.local/bin" "/home/thomas/.bin" "/usr/local/bin" "/bin" "/sbin" "/usr/bin" "/usr/sbin" "/opt/emacs-dev/libexec/emacs/29.0.50/x86_64-pc-linux-gnu")
python-shell-interpreter: "/home/thomas/miniconda/bin/python"
python-shell-virtualenv-root: nil
flycheck-flake8rc: (".flake8" "setup.cfg" "tox.ini")
flycheck-python-flake8-executable: "/bin/flake8"
flycheck-pylintrc: "/home/thomas/.pylintrc"
flycheck-python-pylint-executable: "/home/thomas/miniconda/bin/pylint"
flycheck-python-mypy-executable: nil
flycheck-python-mypy-config: ("mypy.ini" ".mypy.ini" "pyproject.toml" "setup.cfg" "/home/thomas/.config/mypy/config")
flycheck-python-mypy-python-executable: "/home/thomas/miniconda/bin/python"
flycheck-python-pyright-executable: nil
flycheck-python-pycompile-executable: "/home/thomas/miniconda/bin/python"
lsp-jedi-executable-command:
pet config
(use-package pet
;; https://github.com/wyuenho/emacs-pet
;; M-x pet-verify-setup
:quelpa (pet :fetcher github :repo "wyuenho/emacs-pet")
;; :hook (python-mode)
:custom
(pet-toml-to-json-program "tomljson")
(pet-yaml-to-json-program "yq")
:config
(add-hook 'python-mode-hook
(lambda ()
(setq-local python-shell-interpreter (pet-executable-find "python")
python-shell-virtualenv-root (pet-virtualenv-root))
(pet-flycheck-setup)
(flycheck-mode 1)
;; (setq-local lsp-jedi-executable-command
;; (pet-executable-find "jedi-language-server"))
;; (setq-local lsp-pyright-python-executable-cmd python-shell-interpreter
;; lsp-pyright-venv-path python-shell-virtualenv-root)
;; (lsp)
;; (setq-local dap-python-executable python-shell-interpreter)
(setq-local python-pytest-executable (pet-executable-find "pytest"))
;; (when-let ((black-executable (pet-executable-find "black")))
;; (setq-local python-black-command black-executable)
;; (python-black-on-save-mode 1))
(when-let ((isort-executable (pet-executable-find "isort")))
(setq-local python-isort-command isort-executable)
(python-isort-on-save-mode 1)))))
Description
When using pet-mode
with jupyter
(emacs-jupyter), entering an org-edit-special
buffer results in pyenv exited with status 127 [3 times]
(as observed in the *Messages*
buffer when turning on pet-debug
).
This behaviour causes several issues for me when using jupyter
notebooks in org-mode, in particular a few seconds of lag when I try to add a new line with RET or indent a line with TAB (as org-mode opens an org-edit-special
buffer in the background with python-mode
on to get the "correct" indentation behaviour).
Reproduction steps
(setq native-comp-async-report-warnings-errors nil)
(use-package org
:elpaca nil
:init
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)))
:custom
(org-confirm-babel-evaluate nil)
(org-src-fontify-natively t)
(org-edit-src-content-indentation 2))
(use-package jupyter
:elpaca t
:init
(setq native-comp-jit-compilation-deny-list '("jupyter-channel.*.el")) ; Needed to ignore a recent bug on main
(org-babel-do-load-languages
'org-babel-load-languages
(append org-babel-load-languages '((jupyter . t))))
(setq org-babel-default-header-args:jupyter-python '((:async . "yes")
(:session . "py")
(:kernel . "python3"))))
(use-package pet
:elpaca t
:hook
(python-mode . python-pet-hook)
:init
(defun python-pet-hook ()
(pet-mode)))
notebook.org
(adjust kernel name in the notebook if needed):PROPERTIES:
:header-args:python: :async yes :kernel python3 :session py
:END:
#+begin_src python
print("Hello world!")
#+end_src
RET
to add new lineC-c '
to open an org-edit-special
bufferTAB
to indent a line*Messages*
buffer if pet-debug
is turned on)Expected behavior
No lagged behaviour when doing any of the actions in step 4 above, no error message even when pet-debug
is on. This expected behaviour is observed when pet-mode
is removed from the python-mode-hook
.
PET version
2023-06-21 version from MELPA
Emacs version
GNU Emacs 29.0.91 (build 1, x86_64-apple-darwin22.3.0, NS appkit-2299.40 Version 13.2.1 (Build 22D68)) of 2023-06-05
(Installed via emacs-plus, although I have tested this on a different machine with WSL2 and observed the same behaviour).
Desktop
System tools versions
Additional context
Result of M-x (pet-verify-setup)
in the org-edit-special
buffer:
python-shell-interpreter: ~/.pyenv/versions/3.10.5/bin/python
python-shell-virtualenv-root: ~/.venv/
flycheck-python-flake8-executable: unbound
flycheck-pylintrc: unbound
flycheck-python-pylint-executable: unbound
flycheck-python-mypy-executable: unbound
flycheck-python-mypy-config: unbound
flycheck-python-mypy-python-executable: unbound
flycheck-python-pyright-executable: unbound
flycheck-python-pycompile-executable: unbound
lsp-jedi-executable-command: jedi-language-server
lsp-pyls-plugins-jedi-environment: ~/.venv/
lsp-pylsp-plugins-jedi-environment: ~/.venv/
lsp-pyright-python-executable-cmd: ~/.pyenv/versions/3.10.5/bin/python
lsp-pyright-venv-path: ~/.venv/
dap-python-executable: ~/.pyenv/versions/3.10.5/bin/python
python-pytest-executable: pytest
python-black-command: black
blacken-executable: black
python-isort-command: ~/.local/bin/isort
yapfify-executable: ~/.local/bin/yapf
eglot-server-programs (Python part only):
(not available because eglot is not loaded now)
exec-path:
/usr/local/Cellar/pyenv-virtualenv/1.2.1/shims
~/.pyenv/shims
~/.pyenv/bin
~/.poetry/bin
/usr/local/sbin
/usr/local/opt/node@14/bin
~/.local/bin
~/bin
/usr/local/bin
/opt/local/bin
/opt/local/sbin
/Library/Frameworks/Python.framework/Versions/3.7/bin
/Library/Frameworks/Python.framework/Versions/3.8/bin
/usr/local/bin
/System/Cryptexes/App/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/Library/TeX/texbin
/Applications/quarto/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin
/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
/usr/local/Cellar/pyenv-virtualenv/1.2.1/shims
~/.pyenv/bin
~/.poetry/bin
/usr/local/sbin
/usr/local/opt/node@14/bin
~/.local/bin
~/bin
/opt/local/bin
/opt/local/sbin
/Library/Frameworks/Python.framework/Versions/3.7/bin
/Library/Frameworks/Python.framework/Versions/3.8/bin
~/.cargo/bin
~/miniconda3/condabin
~/.erg/bin
~/.erg/bin
/usr/local/Cellar/emacs-plus@29/29.0.90/libexec/emacs/29.0.91/x86_64-apple-darwin22.3.0
Hope this is sufficiently clear, otherwise please let me know what other information I should provide. I can also provide a short video showing the lagged behaviour if required.
This is a more precise statement of a problem which I still believe might be solvable with PET. I use pylsp with several plugins (flake8, mypy, ruff), but mypy is called with the global environment. Local checks on the shell return no errors, but opening the file in Emacs does.
I have the following configuration: pylsp, pylsp-mypy, pylsp-ruff; on Emacs eglot and PET. Eglot configuration is done on user-basis with the following setting:
(setq-default eglot-workspace-configuration
'(:pylsp (:plugins
(:mypy (:enabled t)
:flake8 (:enabled t
:ignore ["E501"])
:pycodestyle (:enabled :json-false)
:ruff (:enabled t
:extendSelect ["D" "E" "E201"]
:extendIgnore ["E741" ])))))
The output of eglot-show.workspace-configuration
yields:
{
"pylsp": {
"plugins": {
"mypy": {
"enabled": true
},
"flake8": {
"enabled": true,
"ignore": [
"E501"
],
"executable": "/usr/bin/flake8"
},
"pycodestyle": {
"enabled": false
},
"ruff": {
"enabled": true,
"extendSelect": [
"D",
"E",
"E201"
],
"extendIgnore": [
"E741"
]
},
"jedi": {
"environment": "/home/jv/spiced/DeScribble/.venv/"
},
"pylint": {
"executable": null
}
}
}
}
So there are some observations:
pet-lookup-eglot-server-initialization-options
. I do not know if this a problem, but at least we have an intransparent modification of a configuration variable here.In Emacs, mypy complains about missing imports which are de facto imported, and about which mypy does not complain when called from the command line.
I hope this is something PET related (maybe we could use an "environment" variable?); if not, I would be glad to profit from your expertise and get some pointers how to further investigate this issue. Configuring this lsp stuff is not a very amusing thing, it feels more like magic because of all the different layers involved.
Feels like a bit of a stupid question, but while conda/mamba/micromamba aren't listed in the README as supported, I can see that there's code handling them in pet.el. I tried getting pet-mode working with my micromamba setup and haven't had any luck, just wanted to know if I should keep trying at this or if conda support just isn't fully working yet.
Description
After adding pet (use-package pet :ensure t) I'm getting a tonne of this in Messages
File mode specification error: (error Autoloading file /Users/mit5893/.emacs.d/elpa/pet-20230423.2326/pet.elc failed to define function pet)
Expected behavior
... not to see an error :)
PET version
20230423 from melpa
Emacs version
30.0.50 (probably an alpha or beta build using homebrew on Mac)
FWIW:
bash-3.2$ grep defun pet.el
(defun pet-system-bin-dir ()
(defun pet-report-error (err)
(defun pet-project-root ()
(defun pet-find-file-from-project-root (file)
(defun pet-locate-dominating-file (file)
(defun pet-find-file-from-project-root-recursively (file)
(defun pet-find-file-from-project (file)
(defun pet-parse-json (str)
(defun pet-parse-config-file (file-path)
(defun pet-make-config-file-change-callback (cache-var parser)
(defun pet-watch-config-file (config-file cache-var parser)
(defun ,(intern path-accessor-name) ()
(defun ,(intern accessor-name) ()
(defun pet-use-pre-commit-p ()
(defun pet-use-conda-p ()
(defun pet-use-poetry-p ()
(defun pet-use-pyenv-p ()
(defun pet-use-pipenv-p ()
(defun pet-pre-commit-config-has-hook-p (id)
(defun pet-parse-pre-commit-db (db-file)
(defun pet-pre-commit-virtualenv-path (hook-id)
(defun pet-executable-find (executable)
(defun pet-virtualenv-root ()
(defun pet-flycheck-python-pylint-find-pylintrc ()
(defun pet-flycheck-checker-get-advice (fn checker property)
(defun pet-flycheck-toggle-local-vars ()
(defun pet-flycheck-setup ()
(defun pet-flycheck-teardown ()
(defun pet-buffer-local-vars-setup ()
(defun pet-buffer-local-vars-teardown ()
(defun pet-verify-setup ()
(defun pet-cleanup-watchers-and-caches ()
Description
The process-lines
call in penultimate branch of pet-executable-find
passes which
and the command as args to pyenv
, which fails.
Reproduction steps
Have pyenv
installed. Install a package with a var that pet
will set, for example, python-black-command
when using python-black
Emacs package.
Now, outside of a virtual env/poetry project when opening a Python file (this is the (executable-find "pyenv")
branch), the call (process-lines "pyenv" "which" "black")
during pet-executable-find
errors out and sets python-black-command
to nil. This doesn't seem to be a path issue, since alternatively (shell-command-to-string "pyenv which black")
succeeds.
Expected behavior
I'm not sure why process-lines
fails here ((process-lines "pyenv" "help")
for example, succeeds), however, I'd expect pet
not to set a variable that could otherwise have a working default value ("black"
in this case if it is in path).
PET version
1.1.0
Emacs version
29
Desktop (please complete the following information):
System tools versions
Additional context
Debugger entered--Lisp error: (error "pyenv exited with status 1")
error("%s exited with status %s" "pyenv" 1)
(if (eq status 0) nil (error "%s exited with status %s" program status))
(if status-handler (funcall status-handler status) (if (eq status 0) nil (error "%s exited with status %s" program status)))
(let ((status (apply #'call-process program nil (current-buffer) nil args))) (if status-handler (funcall status-handler status) (if (eq status 0) nil (error "%s exited with status %s" program status))) (goto-char (point-min)) (let (lines) (while (not (eobp)) (setq lines (cons (buffer-substring-no-properties (line-beginning-position) (line-end-position)) lines)) (forward-line 1)) (nreverse lines)))
(progn (let ((status (apply #'call-process program nil (current-buffer) nil args))) (if status-handler (funcall status-handler status) (if (eq status 0) nil (error "%s exited with status %s" program status))) (goto-char (point-min)) (let (lines) (while (not (eobp)) (setq lines (cons (buffer-substring-no-properties (line-beginning-position) (line-end-position)) lines)) (forward-line 1)) (nreverse lines))))
(unwind-protect (progn (let ((status (apply #'call-process program nil (current-buffer) nil args))) (if status-handler (funcall status-handler status) (if (eq status 0) nil (error "%s exited with status %s" program status))) (goto-char (point-min)) (let (lines) (while (not (eobp)) (setq lines (cons (buffer-substring-no-properties ... ...) lines)) (forward-line 1)) (nreverse lines)))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (let ((status (apply #'call-process program nil (current-buffer) nil args))) (if status-handler (funcall status-handler status) (if (eq status 0) nil (error "%s exited with status %s" program status))) (goto-char (point-min)) (let (lines) (while (not (eobp)) (setq lines (cons ... lines)) (forward-line 1)) (nreverse lines)))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (let ((status (apply ... program nil ... nil args))) (if status-handler (funcall status-handler status) (if (eq status 0) nil (error "%s exited with status %s" program status))) (goto-char (point-min)) (let (lines) (while (not ...) (setq lines ...) (forward-line 1)) (nreverse lines)))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
process-lines-handling-status("pyenv" nil "which" "black")
process-lines("pyenv" "which" "black")
elisp--eval-last-sexp(nil)
eval-last-sexp(nil)
funcall-interactively(eval-last-sexp nil)
command-execute(eval-last-sexp)
As promised in #4, I have tested the updated version at work - and it does work.
However, the project there is structured differently and unless I move/symlink pyproject.toml
to the project root (where .git folder is), then it fails to find it (to be expected).
It would be very helpful to allow to specify additional places where to look for these files (pyproject.toml
, Pipfile
, etc.). E.g. my work project is structured as follows:
project root
|-- .git
|-- README.md
|-- src
|-- pyproject.toml
|-- main
|-- main.py
...
So it would be really helpful if I could specify, whether per project or globally using some variable, that pet
should search not only in the project root but also in ${project root}/src.
My other work projects that use Pipenv
have a similar problem - the Pipfile
is not at the root of the project for organizational reasons - there are multiple subprojects there and only part of them use Python.
I realize a large part of this project is to auto identify venvs, but wondering if theres a possibility of a manual mode? Where the user can provide a path to a venv directory or choose from a list of available venvs
There are times where I'm working on a single script that doesnt have all the scaffolding of an actual project, and I just want to temporarily borrow a venv from somewhere else (as it might have linters etc setup already). Or if I'm working in a project with its own venv but want to switch to another venv temporarily as it has different versions of dependencies
The closest Ive been able to find is pyvenv, but it doesnt change the paths for all the tools (flycheck, lsp etc)
Description
I use the built-in python mode (Emacs 28.1) and I get an error when I call python-shell-send-buffer, because in python.el there is code like:
(with-temp-buffer
(python-mode)
...
Pet adds the function pet-flycheck-python-pylint-find-pylintrc to the mode hook and within this function the call buffer-file-name returns nil and an error is thrown.
**Desktop **
System tools versions
Description
Pipenv virtualenv detection does not work right, even though the Pipfile
and pipenv
itself are found just fine.
Reproduction steps
arbitrary-config-file-path branch
for pet
Pipfile
isn't placed in the project root but in a subdirectory and a Python source file is in a subfolder below the Pipfile
.root
|-- project1
|-- Pipfile
|-- src
|-- main.py
pet-mode
(pet-virtualenv-root)
points to the wrong place, (pet-use-pipenv-p)
returns path to pipenv
, (pet-pipfile)
returns content of the Pipfile
Expected behavior
Correct virtualenv is choosen.
PET version
arbitrary-config-file-path branch
, 21c2933
Emacs version
29.1, self-built
Desktop (please complete the following information):
System tools versions
pre-commit
Additional context
It seems the problem stems from this bit of code in pet-virtualenv-root
:
((when-let ((program (pet-use-pipenv-p)))
(condition-case err
(with-temp-buffer
(let ((exit-code (call-process program nil t nil "--venv"))
(output (string-trim (buffer-string))))
(if (zerop exit-code)
(prog1 output
(setf (alist-get root pet-project-virtualenv-cache nil nil 'equal) output))
(user-error (buffer-string)))))
(error (pet-report-error err)))))
This will try to execute pipenv --venv
from whichever directory Emacs is in when visiting the python file but that does not work! One has to start pipenv
from the directory where the Pipfile
is located, otherwise it just fails, or, worse, in some cases generates a new Pipfile
in the current folder (not for the --venv
command, though).
This is different from poetry
- poetry
will return the correct virtual env even when started from a folder below the pyproject.toml
where the visited source file is. Pipenv will not.
Generally speaking, I think it would be safest to execute these tools from the folder where their corresponding config file is, even if it is not required e.g. for poetry
(no idea about pdm
or pipx
, I don't use them).
BTW, this is broken also on the main branch, if one uses a project that has source files in a subfolder and not right next to the Pipfile
.
Description
I normally create my virtualenvs with python3 -m venv .
, this places the bin/
and lib/
directly inside the project root. Handy, as you now have bin/pip
and don't have to do venv/bin/pip
.
PET doesn't detect this. It looks for venv/
or .venv/
in the project root. Granted, those directories are recommended in the python documentation, but I think I see the .
-method quite a lot. At least in the projects inside my company :-)
Reproduction steps
git init
to make it recognizable for projectile.python3 -m venv .
touch some_script.py
some_script.py
pet-verify-setup
, python-shell-interpreter
will be your system python, not the bin/python
inside the project dir.Expected behavior
I expected python-shell-interpreter
to be the bin/python
inside the project dir.
After reading the PET lisp code, I discovered that PET looks for venv/env/.env. Creating the virtualenv with python3 -m venv venv
made everything work like a charm.
Versions
PET 20230906.46
, emacs 29.1
on osx (but those details won't matter I guess)
Possible solutions
I think it is perfectly OK to require the virtualenv to be in venv/env/.venv. The detection mechanism might be hard to get right otherwise, I fear.
If that is indeed the case, an short addition to the README (noting that the virtualenv has to be in venv/env/.venv) might be handy.
Hello,
I can't manage to get (pet-use-poetry-p)
to ever detect poetry
.
The problem seems to be in this block that always returns nil:
(and (not
(null
(string-match-p
"poetry"
(or (let-alist (pet-pyproject)
.build-system.build-backend)
""))))
(executable-find "poetry"))
The string-match-p
always returns nil, so the and
shortcircuits and the executable is never found, despite poetry
being in the path. If I remove everything apart from the executable-find
, then everything works as expected.
How to reproduce:
virtualenvs.in-project
settings has default value null
and thus virtualenvs are not created inside of the project directory (otherwise the code finds the .venv
directory instead of going through the poetry
detection).emacs
and enable pet-mode
.(pet-use-poetry-p)
will evaluate to nil
pet-virtualenv-root
is nil
Thank you for creating this package! It is great and works with most Python packages I use. However I encountered some problems while extending pet
's support to Eglot and Eshell. I want to discuss them here (I have already made some efforts).
I appreciate that pet
works with so many virtual environment managers. Currently I only use Python's built-in venv
, and have a .venv
directory in all of my Python projects. I want packages like python-pytest
and flycheck
automatically pick executables and packages from the .venv
directory, which is handled pretty well by pet
.
Eglot is a light-weight implementation of LSP (language server protocol) inside Emacs, and is built-in since Emacs 29. I use Eglot to communicate with an external language server (pylsp
in my case), and the language server can do all sort of things for me, like providing completion via rope
, formatting my buffer via black
, linting my buffer via mypy
and ruff
, etc..
By default, eglot
just find the pylsp
executable via executable-find
, and launch it as the language server. However, this by default launches the global pylsp
executable, instead of the local one inside the virtual environment. Thus, the global language server cannot recognize the local packages inside the virtual environment (because they are not installed globally), and cannot do its works like linting and providing completions properly.
Can pet
solve this? definitely! I solved the problem with the following steps:
eglot-ensure
to python-mode-hook
(or python-ts-mode-hook
if tree-sitter is enabled) with a depth of 100, so that eglot
is always enabled after pet
.eglot--executable-find
function with the pet
counterpart, like this.Now Eglot can use the local pylsp
as expected, only with one drawback: it does not work on TRAMP, because pet-executable-find
does not work on TRAMP. Luckily, #20 solves this. Hope it be merged soon.
My problem is: should my workaround be pet
's default behavior? Since Eglot is very popular (maybe more popular than those other packages that pet
supports, as it is built-in now), adding its support may not be a bad idea. If you think so, I can create a PR on this.
When working on my Python projects, sometimes I have to interact with a shell, for example when I have to create the virtual environemnt with python -m venv .venv
, or when I have to install new packages into the virtual environment with pip install
, or even when I try to test my package's CLI with python -m my_awesome_module
. I don't know if this is only my own unique demand, but I need a shell quite a lot.
First I try to use the eshell
, but eshell
cannot activate a virtual environment via activate .venv/bin/activate
, as eshell
does not execute Bash commands.
After that, I tried shell
. In shell
, I can activate the virtual environment manually. But, oh god, why do I have to do things manually as an Emacser? So I wrote these code to auto-activate the Python virtual environments, if there is one in the default-directory
(It is also worth noting that VS Code does this by default).
It seems fine, but:
pet
(which I did want to, but I didn't know how, because I'm not sure if every virtual environment manager offer an "activate" script).eshell
, it is very Lispy, and provides consistent behavior on every platform I use. I shoudn't be forced to use shell
on such basic need, and shell
even cannot work properly with PowerShell on Windows. There must be some other workaround for eshell
.The final solution to this must be integrating pet
into eshell
. virtualenvwrapper is already able to make shell
, eshell
and any other subprocesses aware of the Python virtual environment, despite it support less virtual environment managers than pet
.
I do want to make pet
perfect (so that you don't have to install a crazy amount of virtual environment packages), so I expect an opportunity to thouroughly discuss these problems. If a preferred method is found, I would be more than willing to implement it and create a pull request.
At first I should say your package is awesome, thank you!
But I faced and issue with my workflow - in one of the projects I worked on I'm running pytest tests inside docker. So I set python-pytest-command
to something like docker-compose run pytest-service pytest
. So for this particular project I want to exclude python-pytest-command
from ones which affected by venv. Is it possible to make some settings which allow me to do it?
Description
I have the problem that my pet setup has some performance issue, i.e., it takes a long time in every python buffer in my project until the python-mode-hook
functions are run. I think this is the case since I've started using pet.
This code in my python-mode-hook
takes 640ms! when I open a python file and when I revert the buffer
(setq-local python-shell-interpreter (pet-executable-find "python")
python-shell-virtualenv-root (pet-virtualenv-root)))
What I also see is that if I execute in my scratch buffer, I see that it take > 600ms.
(defmacro thi::with-timer (title &rest forms)
"Run the given FORMS, counting the elapsed time.
A message including the given TITLE and the corresponding elapsed
time is displayed."
(declare (indent 1))
(let ((nowvar (make-symbol "now"))
(body `(progn ,@forms)))
`(let ((,nowvar (current-time)))
(message "%s..." ,title)
(prog1 ,body
(let ((elapsed
(float-time (time-subtract (current-time) ,nowvar))))
(message "%s... done (%.3fs)" ,title elapsed))))))
(thi::with-timer "pet-exec + virt find"
(let ((default-directory "/home/thomas/gitrepos/any-git-repo"))
(pet-executable-find "python")
(pet-virtualenv-root)))
setting the default directory just to my home dir reduces the time to just 30 to 40ms (still a lot IMO).
Reproduction steps
Expected behavior
I see that pet related functions in my python mode hook + (flycheck-mode 1)
take a long time (>2s).
If I open a python file that is not part of any project, I don't have this problem.
PET version
pet 20220917.2111 installed Executable and virtualenv tracker for python-mode
Emacs version
29.0.5
Desktop (please complete the following information):
see #10
System tools versions
see #10
But here's a patch that fixes it!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.