GithubHelp home page GithubHelp logo

wyuenho / emacs-pet Goto Github PK

View Code? Open in Web Editor NEW
64.0 64.0 9.0 362 KB

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

Emacs Lisp 99.62% Makefile 0.38%
emacs python virtualenv

emacs-pet's People

Contributors

egelja avatar walheimat avatar wyuenho avatar zyxir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

emacs-pet's Issues

Support flymake?

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

  • PET latest version
  • Emacs 29.1 with eglot
  • Python and mypy latest version
  • Standard installation of PET, as recommended in the doc (by using setq-locale and the hook python-base-mode-hook.

Cannot kill python script buffer if outside a project (projectile)

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 :

  • OS: Windows 10

System tools versions

  • dasel [e.g. v1.26.0]

Unable to guess virtualenv

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.

Source:

(when-let* ((root (pet-project-root))

Conflict between precommit and poetry

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):

  • OS: Linux Mageia 8, Windows 10

System tools versions

  • dasel v1.26.0

pet-find-file-in-project problem with regex in filename

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):

  • OS: ubuntu
  • Version 2022.04

Running pet-verify-setup outputs some warnings/messages in *Messages*

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):

  • OS: ubuntu
  • Version 22.04
  • emacs 29.0.50

System tools versions

  • dasel [ ]
  • sqlite3 [ ]
  • yq [4.26.1]
  • toml [1.9.4]

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)))))

pyenv exited with status 127 when using pet-mode with emacs-jupyter

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

  1. Minimum config
init.el
(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)))
  1. Ensure you have Jupyter installed on your machine and have at least one basic working python3 kernel.
  2. Open/create new notebook.
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
  1. Do one of the following:
    a. Press RET to add new line
    b. Press C-c ' to open an org-edit-special buffer
    c. Press TAB to indent a line
  2. Observe the lagged behaviour (and the error message in *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

  • OS: MacOS
  • Version: Ventura 13.4 (22F66)

System tools versions

  • pyenv v2.3.18

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.

pylsp-mypy is not recognizing the virtual environment

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 works fine, adding the virtual environment directory e.g. to jedi
  • The initial configuration variable did not set jedi nor pylint. These entries are added by PET (in the function 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.
  • mypy, however, is not called correctly; but it works with the activated environment on the command line.

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.

Does conda work?

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.

pet-20230423.2326/pet.elc failed to define function pet

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 ()

`pet-exectuable-find` calls of `process-lines` using `pyenv which` can fail, setting vars to `nil`

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):

  • OS: Ubuntu
  • Version 22.04

System tools versions

  • dasel v1.26.1
  • sqlite3 3.37.2
  • yq -
  • toml -

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)

Allow the location of pyproject.toml/Pipfile etc. to be customized

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.

Manual venv selection?

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)

Error when calling python-shell-send-buffer

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 **

  • OS: Windows 10

System tools versions

  • dasel [e.g. v1.26.0]

Pipenv virtualenv detection does not work properly

Description
Pipenv virtualenv detection does not work right, even though the Pipfileand pipenv itself are found just fine.

Reproduction steps

  1. Use the arbitrary-config-file-path branch for pet
  2. Create a project where the 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
  1. Open the python file
  2. Enable pet-mode
  3. (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):

  • OS: Linux Ubuntu under WSL2
  • Version 20.04.4 LTS

System tools versions

  • dasel 1.26.0
  • sqlite3 - none, but not using pre-commit
  • yq - none
  • toml - none

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.

Virtualenv is not detected when it is directly in the root directory

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

  • Emacs with PET and projectile and so.
  • Some dir where you've done git init to make it recognizable for projectile.
  • python3 -m venv .
  • touch some_script.py
  • Start emacs, open some_script.py
  • Check 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.

(pet-use-poetry-p) doesn't find poetry

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:

  • Create Poetry project with the default config, make sure the 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).
  • Open the python file in emacs and enable pet-mode.
  • (pet-use-poetry-p) will evaluate to nil
  • pet-virtualenv-root is nil

Add support for Eglot (and maybe Eshell)

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).

My workflow

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.

Problem 1: Eglot integration

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:

  1. Add 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.
  2. Advice the 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.

Problem 2: Eshell or Shell integration

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:

  1. My workaround is my own magical hack. I didn't use 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).
  2. My workaround is ugly. I love 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.

Made list of changed variables configurable

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?

Pet performance issue

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

  1. open a python file in a project that has (.pre-commit-config.yaml and a environment.yml)

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.