{"id":21902399,"url":"https://github.com/wyuenho/emacs-pet","last_synced_at":"2025-04-04T23:07:35.281Z","repository":{"id":55030761,"uuid":"512950248","full_name":"wyuenho/emacs-pet","owner":"wyuenho","description":"Tracks down the correct Python tooling executables from your virtualenvs so you can glue the binaries to Emacs and delete code in init.el","archived":false,"fork":false,"pushed_at":"2025-01-15T06:37:48.000Z","size":462,"stargazers_count":144,"open_issues_count":6,"forks_count":16,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-04T12:49:03.867Z","etag":null,"topics":["emacs","python","virtualenv"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wyuenho.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-12T00:44:37.000Z","updated_at":"2025-03-28T16:49:27.000Z","dependencies_parsed_at":"2023-10-02T02:21:58.354Z","dependency_job_id":"953ebaf5-9ca7-4253-b513-b6140df2fc94","html_url":"https://github.com/wyuenho/emacs-pet","commit_stats":{"total_commits":349,"total_committers":8,"mean_commits":43.625,"dds":0.04871060171919772,"last_synced_commit":"c2278f9bc1c3a5070021fe3251ed09b5a468d331"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyuenho%2Femacs-pet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyuenho%2Femacs-pet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyuenho%2Femacs-pet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyuenho%2Femacs-pet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wyuenho","download_url":"https://codeload.github.com/wyuenho/emacs-pet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247261603,"owners_count":20910108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emacs","python","virtualenv"],"created_at":"2024-11-28T15:18:31.068Z","updated_at":"2025-04-04T23:07:35.260Z","avatar_url":"https://github.com/wyuenho.png","language":"Emacs Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":".. image:: https://github.com/wyuenho/emacs-pet/actions/workflows/ci.yml/badge.svg\n   :target: https://github.com/wyuenho/emacs-pet/actions/workflows/ci.yml\n   :alt: CI Status\n\n**P** ython **E** xecutable **T** racker\n========================================\n\nGreatings fellow Pythonistas and Emacs users!\n\nHave you ever worked on a project that uses one of the many Python package\nmanagers and/or virtual environments, where all the linters, formatters and\ncommit hooks are set up meticulously, and then when you fire up Emacs, packages\nlike `flycheck \u003chttps://www.flycheck.org/en/latest/\u003e`_ or `lsp-mode\n\u003chttps://emacs-lsp.github.io/lsp-mode/\u003e`_ are either unable to find the binary\nin your virtualenv, or are using the wrong one?\n\nHave you ever tried one of the 11+ Emacs virtualenv packages to help you fix\nthis problem, but are still at a lost at why your other favorite Emacs packages\nstill can't find the right binaries, or they stop working when you switch to a\ndifferent project using a different flavor of virtualenv?\n\nIf you answer \"yes\" for any of these questions, you've come to the right place.\n\n\nHow does ``pet`` work?\n----------------------\n\nThe first key insight is to recognize the paths to the executables of many\nPython linting and formatting Emacs packages are configurable.\n\nThe second key insight is Emacs allows you to setup a different value for the\nexectuable path on a per buffer basis, and that these packages work with these\nbuffer-local values.\n\nThe hardest problem is finding the correct executable, this is what ``pet``\ntries to solve.\n\nAs long as you use one of the supported Python virtualenv tools, ``pet`` will be\nable to find the virtualenv root and binary you ask for, with **zero Emacs\nconfiguration** necessary.\n\n``pet`` works well with popular source code project management packages such as\n`Projectile \u003chttps://docs.projectile.mx/projectile/index.html\u003e`_ and the\nbuilt-in ``project.el``. The first time you call one the few ``pet`` helper\nfunctions, it will use Projectile or project.el to detect the root of your\nproject, search for the configuration files for the many supported Python\nvirtualenv tools, and then lookup the location of the virtualenv based on the\ncontent of the configuration files. Once a virtualenv is found, all executables\nare found by looking into its ``bin`` directory.\n\n\nSupported Python Virtual Environment Tools\n------------------------------------------\n\n- `pre-commit \u003chttps://pre-commit.com\u003e`_\n- `poetry \u003chttps://python-poetry.org\u003e`_\n- `pipenv \u003chttps://pipenv.pypa.io\u003e`_\n- `direnv \u003chttps://direnv.net\u003e`_\n- `venv \u003chttps://docs.python.org/3/library/venv.html\u003e`_, `virtualenv\n  \u003chttps://virtualenv.pypa.io\u003e`_ or `virtualenvwrapper\n  \u003chttps://virtualenvwrapper.readthedocs.io\u003e`_ (`virtualenvwrapper caveats`_)\n- `maturin \u003chttps://www.maturin.rs\u003e`_\n- `uv \u003chttps://github.com/astral-sh/uv\u003e`_ (but not tools installed by ``uv tool install``)\n- `pdm \u003chttps://pdm-project.org\u003e`_\n- `pipx \u003chttps://pipx.pypa.io\u003e`_\n- `pyenv \u003chttps://github.com/pyenv/pyenv\u003e`_ (very poorly maintained, don't use\n  it unless you are using Homebrew on macOS)\n- `docker \u003chttps://hub.docker.com/_/python\u003e`_\n- `conda \u003chttps://docs.conda.io\u003e`_\n- `mamba\n  \u003chttps://mamba.readthedocs.io/en/latest/installation/mamba-installation.html\u003e`_\n- `micromamba\n  \u003chttps://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html\u003e`_\n- Whatever is on your ``VIRTUAL_ENV`` environment variable\n- Even when you aren't in a virtual environment\n\n\nSupported Emacs Packages\n------------------------\n\n- Built-in `project.el \u003chttps://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html\u003e`_\n- `projectile \u003chttps://docs.projectile.mx/projectile/index.html\u003e`_\n- `envrc \u003chttps://github.com/purcell/envrc\u003e`_ (`direnv caveats`_)\n- `eglot \u003chttps://github.com/joaotavora/eglot\u003e`_\n- `dape \u003chttps://github.com/svaante/dape\u003e`_\n- `flycheck \u003chttps://www.flycheck.org/en/latest/\u003e`_\n- `lsp-jedi \u003chttps://github.com/fredcamps/lsp-jedi\u003e`_\n- `lsp-pyright \u003chttps://github.com/emacs-lsp/lsp-pyright\u003e`_\n- `dap-python \u003chttps://emacs-lsp.github.io/dap-mode/page/configuration/#python\u003e`_\n- `blacken \u003chttps://github.com/pythonic-emacs/blacken\u003e`_\n- `yapfify \u003chttps://github.com/JorisE/yapfify\u003e`_\n- `python-black \u003chttps://github.com/wbolster/emacs-python-black\u003e`_\n- `python-isort \u003chttps://github.com/wyuenho/emacs-python-isort\u003e`_\n- `python-pytest \u003chttps://github.com/wbolster/emacs-python-pytest\u003e`_\n- `ruff-format \u003chttps://melpa.org/#/ruff-format\u003e`_\n- `py-autopep8 \u003chttps://github.com/emacsmirror/py-autopep8\u003e`_\n- `auto-virtualenvwrapper \u003chttps://github.com/robert-zaremba/auto-virtualenvwrapper.el/\u003e`_\n\n\nSystem Requirements\n-------------------\n\nCurrently ``pet`` requires a program to convert TOML to JSON, a program to\nconvert YAML to JSON, and if you are using Emacs \u003c 29, the ``sqlite3`` command\nto be installed on your system.\n\nBy default, both the TOML to JSON and YAML to JSON converters are configured to\nuse `dasel \u003chttps://github.com/TomWright/dasel\u003e`_.  If you are on Linux, it may\nbe more convenient to use `tomljson\n\u003chttps://github.com/pelletier/go-toml#tools\u003e`_ and `yq\n\u003chttps://github.com/mikefarah/yq\u003e`_ since both of which are likely to be\navailable from the system package management system.\n\nWhen a suitable Emacs Lisp YAML and TOML parser becomes available, ``dasel``\nwill be made optional.\n\n\nUsage\n-----\n\nIf you are using Emacs on macOS, to get the most out of ``pet``, it is best to\ninstall `exec-path-from-shell\n\u003chttps://github.com/purcell/exec-path-from-shell\u003e`_ first to ensure all of the\n`Supported Python Virtual Environment Tools`_ are available in your\n``exec-path``. Once your ``exec-path`` is synced up to your shell's ``$PATH``\nenvironment variable, you can use the following ways to help you setup the rest\nof your Emacs packages **properly**.\n\n\nBasic Setup\n+++++++++++\n\nGenerally, the following snippet is all you'll need:\n\n.. code-block:: elisp\n\n   (require 'pet)\n\n   ;; Emacs \u003c 26\n   ;; You have to make sure this function is added to the hook last so it's\n   ;; called first\n   (add-hook 'python-mode-hook 'pet-mode)\n\n   ;; Emacs 27+\n   ;; The -10 tells `add-hook' to makes sure the function is called as early as\n   ;; possible whenever it is added to the hook variable\n   (add-hook 'python-mode-hook 'pet-mode -10)\n\n   ;; Emacs 29+\n   ;; This will turn on `pet-mode' on `python-mode' and `python-ts-mode'\n   (add-hook 'python-base-mode-hook 'pet-mode -10)\n\nOr, if you use `use-package \u003chttps://github.com/jwiegley/use-package\u003e`_:\n\n.. code-block:: elisp\n\n   (use-package pet\n     :config\n     (add-hook 'python-base-mode-hook 'pet-mode -10))\n\n\nThis will setup the buffer local variables for all of the `Supported Emacs\nPackages`_.\n\n\nAdvanced Usage\n++++++++++++++\n\nIf you need to configure a package that ``pet`` doesn't support, or only want to\nconfigure a couple of packages instead of all of the supported ones, ``pet``\noffers 2 autoloaded functions to help you find the correct path to the\nexecutable and virtualenv directory:\n\n- ``(pet-executable-find EXECUTABLE)``\n- ``(pet-virtualenv-root)``\n\nFor example, to set up ``python-mode`` to use the correct interpreter when you\nexecute ``M-x run-python``:\n\n.. code-block:: elisp\n\n   (add-hook 'python-mode-hook\n             (lambda ()\n               (setq-local python-shell-interpreter (pet-executable-find \"python\")\n                           python-shell-virtualenv-root (pet-virtualenv-root))))\n\n\nFor ``flycheck``, due to its complexity, ``pet`` also comes with another\nautoloaded function to help you setup the ``flake8``, ``pylint`` and ``mypy``\ncheckers:\n\n.. code-block:: elisp\n\n   (add-hook 'python-mode-hook 'pet-flycheck-setup)\n\n\nComplete Example\n++++++++++++++++\n\n.. code-block:: elisp\n\n   (use-package exec-path-from-shell\n     :if (memq (window-system) '(mac ns))\n     :config (exec-path-from-shell-initialize))\n\n   (use-package flycheck)\n\n   (use-package lsp)\n\n   (use-package lsp-jedi\n     :after lsp)\n\n   (use-package lsp-pyright\n     :after lsp)\n\n   (use-package dap-python\n     :after lsp)\n\n   (use-package eglot)\n\n   (use-package python-pytest)\n\n   (use-package python-black)\n\n   (use-package python-isort)\n\n   (use-package ruff-format)\n\n   (use-package pet\n     :ensure-system-package (dasel sqlite3)\n     :config\n     (add-hook 'python-mode-hook\n               (lambda ()\n                 (setq-local python-shell-interpreter (pet-executable-find \"python\")\n                             python-shell-virtualenv-root (pet-virtualenv-root))\n\n                 ;; (pet-eglot-setup)\n                 ;; (eglot-ensure)\n\n                 (pet-flycheck-setup)\n                 (flycheck-mode)\n\n                 (setq-local lsp-jedi-executable-command\n                             (pet-executable-find \"jedi-language-server\"))\n\n                 (setq-local lsp-pyright-python-executable-cmd python-shell-interpreter\n                             lsp-pyright-venv-path python-shell-virtualenv-root)\n\n                 (lsp)\n\n                 (setq-local dap-python-executable python-shell-interpreter)\n\n                 (setq-local python-pytest-executable (pet-executable-find \"pytest\"))\n\n                 (when-let ((ruff-executable (pet-executable-find \"ruff\")))\n                   (setq-local ruff-format-command ruff-executable)\n                   (ruff-format-on-save-mode))\n\n                 (when-let ((black-executable (pet-executable-find \"black\")))\n                   (setq-local python-black-command black-executable)\n                   (python-black-on-save-mode))\n\n                 (when-let ((isort-executable (pet-executable-find \"isort\")))\n                   (setq-local python-isort-command isort-executable)\n                   (python-isort-on-save-mode)))))\n\n\nFAQ\n---\n\n.. _direnv caveats:\n\nHow do I get ``pet`` to pick up the virtualenv or PATH created by ``direnv``?\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nShort answer:\n\nUse `envrc \u003chttps://github.com/purcell/envrc\u003e`_.\n\n.. code-block:: elisp\n\n   (require 'envrc)\n   (add-hook 'change-major-mode-after-body-hook 'envrc-mode)\n\n\nLonger answer:\n\nThere are a number of packages similar to ``envrc`` such as ``direnv`` and\n``buffer-env`` that claim to be able to configure ``direnv`` in Emacs. However,\nthey all suffer from various problems such as changing the environment and\n``exec-path`` for the entire Emacs process, unable to activate early enough or\nbeing too general to support direnv tightly.\n\nBecause ``pet`` needs to configure the buffer local variables **before** the\nrest of the minor modes are activated, but **after** ``exec-path`` has been set\nup by direnv, one must take care of choosing a minor mode package that allows\nthe user to customize when it takes effect. This requirement rules out\n``direnv.el`` [1]_.\n\n.. [1] Earlier versions of ``pet`` suggested ``direnv.el`` as a solution, it is\n       no longer recommended due to this reason.\n\n.. _virtualenvwrapper caveats:\n\nMy project uses ``virtualenvwrapper``, how do I get ``pet`` to pick up the virtualenv?\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nYou can use ``envrc`` + `this direnv configuration\n\u003chttps://github.com/direnv/direnv/wiki/Python#virtualenvwrapper\u003e`_ to activate\nyour virtualenv or `auto-virtualenvwrapper\n\u003chttps://github.com/robert-zaremba/auto-virtualenvwrapper.el/\u003e`_. Note that in\nany case, your virtualenv must be activated before turning on ``pet-mode`` in\norder to make the environment variable ``VIRTUAL_ENV`` available to it. For\nexample:\n\n.. code-block:: elisp\n\n   (require 'auto-virtualenvwrapper)\n   (require 'pet)\n\n   (add-hook 'python-base-mode-hook\n     (lambda ()\n       (auto-virtualenvwrapper-activate)\n       (pet-mode))\n     -10)\n   (add-hook 'window-configuration-change-hook #'auto-virtualenvwrapper-activate)\n   (add-hook 'focus-in-hook #'auto-virtualenvwrapper-activate)\n\n\nWhy didn't ``pet`` set up the executable variables on a fresh Python project clone?\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n``Pet`` does not automatically create virtualenvs for you. If you have a fresh\nclone, you must create the virtualenv and install your development dependencies\ninto it first. Once it is done, the next time you open a Python file buffer\n``pet`` will automatically set up the executable variables for you.\n\nTo find out how to do it, please find the virtualenv tool in question from\n`Supported Python Virtual Environment Tools`_, and visit its documentation for\ndetails.\n\n\nWhy doesn't ``pet`` simply set a buffer-local ``exec-path``?\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nThe reason is mainly due to the fact that many Python projects use development\ntools located in different virtualenvs. This means ``exec-path`` needs to be\nprepended with all of the virtualenvs for all of the dev tools, and always kept\nin the correct order. An example where this approach may cause issues is dealing\nwith projects that use ``pre-commit`` and ``direnv``. A typical ``pre-commit``\nconfiguration may include many \"hooks\", where each of them is isolated in its\nown virtualenv. While prepending many directories to ``exec-path`` is not\nproblematic in itself, playing well with other Emacs packages that mutate\n``exec-path`` reliably is non-trivial. Providing an absolute path to executable\nvariables conveniently sidesteps this complexity, while being slightly more\nperformant.\n\nIn addition, there are Emacs packages, most prominantly ``flycheck`` that by\ndefault require dev tools to be installed into the same virtualenv as the first\n``python`` executable found on ``exec-path``. Changing this behavior requires\nsetting the corresponding ``flycheck`` checker executable variable to the\nintended absolute path.\n\n\nMy package didn't pick up the correct paths, how do I debug ``pet``?\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nYou can turn on ``pet-debug`` and watch what comes out in the ``*Messages*``\nbuffer. In addition, you can use ``M-x pet-verify-setup`` in your Python buffers\nto find out what was detected.\n\nFor ``lsp``, use ``lsp-describe-session``.\n\nFor ``eglot``, use ``eglot-show-workspace-configuration``.\n\nFor ``flycheck``, use ``flycheck-verify-setup``.\n\n\nDo I still need any of the 11+ virtualenv Emacs packages?\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nNope. You can uninstall them all. This is the raison d'être of this package.\n\n\nLicense\n-------\n\n`GPLv3 \u003c./LICENSE\u003e`_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwyuenho%2Femacs-pet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwyuenho%2Femacs-pet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwyuenho%2Femacs-pet/lists"}