pax_global_header00006660000000000000000000000064145056747030014525gustar00rootroot0000000000000052 comment=3e3b9958f5cf6b388cfe3d8650f223e5406f5128 pyvenv-el-1.21+git20211014.31ea715/000077500000000000000000000000001450567470300157545ustar00rootroot00000000000000pyvenv-el-1.21+git20211014.31ea715/.bumpversion.cfg000066400000000000000000000002561450567470300210670ustar00rootroot00000000000000[bumpversion] current_version = 1.21 parse = (?P\d+)\.(?P\d+) serialize = {major}.{minor} files = pyvenv.el commit = True tag = True tag_name = v{new_version} pyvenv-el-1.21+git20211014.31ea715/.gitignore000066400000000000000000000000061450567470300177400ustar00rootroot00000000000000.cask pyvenv-el-1.21+git20211014.31ea715/.travis.yml000066400000000000000000000006101450567470300200620ustar00rootroot00000000000000language: emacs-lisp sudo: no env: # - EVM_EMACS=emacs-24.1-travis # - EVM_EMACS=emacs-24.2-travis - EVM_EMACS=emacs-24.3-travis - EVM_EMACS=emacs-24.4-travis - EVM_EMACS=emacs-24.5-travis before_install: - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > travis.sh && source ./travis.sh - evm install $EVM_EMACS --use --skip - cask script: - make test pyvenv-el-1.21+git20211014.31ea715/Cask000066400000000000000000000002711450567470300165600ustar00rootroot00000000000000(source gnu) (source melpa) (package "pyvenv" "1.1" "Python virtualenv support for Emacs") (package-file "pyvenv.el") (development (depends-on "ert-runner") (depends-on "mocker")) pyvenv-el-1.21+git20211014.31ea715/Makefile000066400000000000000000000013401450567470300174120ustar00rootroot00000000000000.PHONY: all test test-all cask EMACS ?= emacs VERSION=$(shell sed -ne 's/^;; Version: \(.*\)/\1/p' pyvenv.el) all: test test: cask exec ert-runner --quiet test-all: clean cask cask exec ert-runner --quiet EMACS=emacs-24.1 cask exec ert-runner --quiet EMACS=emacs-24.2 cask exec ert-runner --quiet EMACS=emacs-24.3 cask exec ert-runner --quiet EMACS=emacs-24.4 cask exec ert-runner --quiet EMACS=emacs-24.5 cask exec ert-runner --quiet cask: cask install EMACS=emacs-24.1 cask install EMACS=emacs-24.2 cask install EMACS=emacs-24.3 cask install EMACS=emacs-24.4 cask install EMACS=emacs-24.5 cask install compile: $(EMACS) -batch -L . -f batch-byte-compile *.el clean: rm -rf .cask dist find -name '*.elc' -delete pyvenv-el-1.21+git20211014.31ea715/README.md000066400000000000000000000024411450567470300172340ustar00rootroot00000000000000# pyvenv.el, Python virtual environment support for Emacs ![Travis-CI Build Status](https://secure.travis-ci.org/jorgenschaefer/pyvenv.png) [![MELPA Stable](http://stable.melpa.org/packages/pyvenv-badge.svg)](http://stable.melpa.org/#/pyvenv) This is a simple global minor mode which will replicate the changes done by virtualenv activation inside Emacs. The main entry points are `pyvenv-activate`, which queries the user for a virtual environment directory to activate, and `pyvenv-workon`, which queries for a virtual environment in `$WORKON_HOME` (from virtualenvwrapper.sh). ## Similar Projects [virtualenv.el](https://github.com/aculich/virtualenv.el) is the original virtualenv implementation for Emacs. I used it for a long time, but didn’t like some of the design decisions. For example, it does not modify `process-environment` so does not set a virtual environment for `M-x compile` and other external processes. Also, `M-x virtualenv-workon` requires a prefix argument to actually change the current virtual environment. And it does not support virtualenvwrapper’s hooks, which I use to set up a working environment. All in all, too much magic for too little gain. So I figured I’d write my own. Still, it’s an excellent package and I’m very grateful to have used it for a long time. pyvenv-el-1.21+git20211014.31ea715/pyvenv.el000066400000000000000000000614551450567470300176400ustar00rootroot00000000000000;;; pyvenv.el --- Python virtual environment interface -*- lexical-binding: t -*- ;; Copyright (C) 2013-2017 Jorgen Schaefer ;; Author: Jorgen Schaefer ;; URL: http://github.com/jorgenschaefer/pyvenv ;; Version: 1.21 ;; Keywords: Python, Virtualenv, Tools ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License ;; as published by the Free Software Foundation; either version 3 ;; of the License, or (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; This is a simple global minor mode which will replicate the changes ;; done by virtualenv activation inside Emacs. ;; The main entry points are `pyvenv-activate', which queries the user ;; for a virtual environment directory to activate, and ;; `pyvenv-workon', which queries for a virtual environment in ;; $WORKON_HOME (from virtualenvwrapper.sh). ;; If you want your inferior Python processes to be restarted ;; automatically when you switch your virtual environment, add ;; `pyvenv-restart-python' to `pyvenv-post-activate-hooks'. ;;; Code: (require 'eshell) (require 'json) (require 'subr-x) ;; User customization (defgroup pyvenv nil "Python Virtual Environment Interface." :prefix "pyvenv-" :group 'languages) (defcustom pyvenv-workon nil "The intended virtualenv in the virtualenvwrapper directory. This is rarely useful to set globally. Rather, set this in file- or directory-local variables using \\[add-file-local-variable] or \\[add-dir-local-variable]. When `pyvenv-mode' is enabled, pyvenv will switch to this virtualenv. If a virtualenv is already enabled, it will ask first." :type 'pyvenv-workon :safe #'stringp :group 'pyvenv) (defcustom pyvenv-activate nil "The intended virtualenv directory. This is rarely useful to set globally. Rather, set this in file- or directory-local variables using \\[add-file-local-variable] or \\[add-dir-local-variable]. When `pyvenv-mode' is enabled, pyvenv will switch to this virtualenv. If a virtualenv is already enabled, it will ask first." :type 'directory :safe #'stringp :group 'pyvenv) (defcustom pyvenv-tracking-ask-before-change nil "Non-nil means pyvenv will ask before automatically changing a virtualenv. This can happen when a new file is opened with a buffer-local value (from file-local or directory-local variables) for `pyvenv-workon' or `pyvenv-workon', or if `pyvenv-tracking-mode' is active, after every command." :type 'boolean :group 'pyvenv) (defcustom pyvenv-virtualenvwrapper-python (or (getenv "VIRTUALENVWRAPPER_PYTHON") (executable-find "python3") (executable-find "python") (executable-find "py") (executable-find "pythonw") "python") "The python process which has access to the virtualenvwrapper module. This should be $VIRTUALENVWRAPPER_PYTHON outside of Emacs, but virtualenvwrapper.sh does not export that variable. We make an educated guess, but that can be off." :type '(file :must-match t) :safe #'file-directory-p :group 'pyvenv) (defcustom pyvenv-exec-shell (or (executable-find "bash") (executable-find "sh") shell-file-name) "The path to a POSIX compliant shell to use for running virtualenv hooks. Useful if you use a non-POSIX shell (e.g. fish)." :type '(file :must-match t) :group 'pyvenv) (defcustom pyvenv-default-virtual-env-name nil "Default directory to use when prompting for a virtualenv directory in `pyvenv-activate'." :type 'string :group 'pyvenv) ;; API for other libraries (defvar pyvenv-virtual-env nil "The current virtual environment. Do not set this variable directly; use `pyvenv-activate' or `pyvenv-workon'.") (defvar pyvenv-virtual-env-path-directories nil "Directories added to PATH by the current virtual environment. Do not set this variable directly; use `pyvenv-activate' or `pyvenv-workon'.") (defvar pyvenv-virtual-env-name nil "The name of the current virtual environment. This is usually the base name of `pyvenv-virtual-env'.") (defvar pyvenv-pre-create-hooks nil "Hooks run before a virtual environment is created.") (defvar pyvenv-post-create-hooks nil "Hooks run after a virtual environment is created.") (defvar pyvenv-pre-activate-hooks nil "Hooks run before a virtual environment is activated. `pyvenv-virtual-env' is already set.") (defvar pyvenv-post-activate-hooks nil "Hooks run after a virtual environment is activated. `pyvenv-virtual-env' is set.") (defvar pyvenv-pre-deactivate-hooks nil "Hooks run before a virtual environment is deactivated. `pyvenv-virtual-env' is set.") (defvar pyvenv-post-deactivate-hooks nil "Hooks run after a virtual environment is deactivated. `pyvenv-virtual-env' is still set.") (defvar pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[" pyvenv-virtual-env-name "] ")) "How `pyvenv-mode' will indicate the current environment in the mode line.") ;; Internal code. (defvar pyvenv-old-process-environment nil "The old process environment that needs to be restored after deactivating the current environment.") (defun pyvenv-create (venv-name python-executable) "Create virtualenv. VENV-NAME PYTHON-EXECUTABLE." (interactive (list (read-from-minibuffer "Name of virtual environment: ") (let ((dir (if pyvenv-virtualenvwrapper-python (file-name-directory pyvenv-virtualenvwrapper-python) nil)) (initial (if pyvenv-virtualenvwrapper-python (file-name-base pyvenv-virtualenvwrapper-python) nil))) (read-file-name "Python interpreter to use: " dir nil nil initial)))) (let ((venv-dir (concat (file-name-as-directory (pyvenv-workon-home)) venv-name))) (unless (file-exists-p venv-dir) (run-hooks 'pyvenv-pre-create-hooks) (cond ((executable-find "virtualenv") (with-current-buffer (generate-new-buffer "*virtualenv*") (call-process "virtualenv" nil t t "-p" python-executable venv-dir) (display-buffer (current-buffer)))) ((= 0 (call-process python-executable nil nil nil "-m" "venv" "-h")) (with-current-buffer (generate-new-buffer "*venv*") (call-process python-executable nil t t "-m" "venv" venv-dir) (display-buffer (current-buffer)))) (t (error "Pyvenv necessitates the 'virtualenv' python package"))) (run-hooks 'pyvenv-post-create-hooks)) (pyvenv-activate venv-dir))) ;;;###autoload (defun pyvenv-activate (directory) "Activate the virtual environment in DIRECTORY." (interactive (list (read-directory-name "Activate venv: " nil nil nil pyvenv-default-virtual-env-name))) (setq directory (expand-file-name directory)) (pyvenv-deactivate) (setq pyvenv-virtual-env (file-name-as-directory directory) pyvenv-virtual-env-name (file-name-nondirectory (directory-file-name directory)) python-shell-virtualenv-path directory python-shell-virtualenv-root directory) ;; Set venv name as parent directory for generic directories or for ;; the user's default venv name (when (or (member pyvenv-virtual-env-name '("venv" ".venv" "env" ".env")) (and pyvenv-default-virtual-env-name (string= pyvenv-default-virtual-env-name pyvenv-virtual-env-name))) (setq pyvenv-virtual-env-name (file-name-nondirectory (directory-file-name (file-name-directory (directory-file-name directory)))))) (pyvenv-run-virtualenvwrapper-hook "pre_activate" nil pyvenv-virtual-env) (run-hooks 'pyvenv-pre-activate-hooks) (setq pyvenv-virtual-env-path-directories (pyvenv--virtual-env-bin-dirs directory) ;; Variables that must be reset during deactivation. pyvenv-old-process-environment (list (cons "PYTHONHOME" (getenv "PYTHONHOME")) (cons "VIRTUAL_ENV" nil))) (setenv "VIRTUAL_ENV" directory) (setenv "PYTHONHOME" nil) (pyvenv--add-dirs-to-PATH pyvenv-virtual-env-path-directories) (pyvenv-run-virtualenvwrapper-hook "post_activate" 'propagate-env) (run-hooks 'pyvenv-post-activate-hooks)) ;;;###autoload (defun pyvenv-deactivate () "Deactivate any current virtual environment." (interactive) (when pyvenv-virtual-env (pyvenv-run-virtualenvwrapper-hook "pre_deactivate" 'propagate-env) (run-hooks 'pyvenv-pre-deactivate-hooks) (pyvenv--remove-dirs-from-PATH (pyvenv--virtual-env-bin-dirs pyvenv-virtual-env)) (dolist (envvar pyvenv-old-process-environment) (setenv (car envvar) (cdr envvar))) ;; Make sure PROPAGATE-ENV is nil here, so that it does not change ;; `exec-path', as $PATH is different (pyvenv-run-virtualenvwrapper-hook "post_deactivate" nil pyvenv-virtual-env) (run-hooks 'pyvenv-post-deactivate-hooks)) (setq pyvenv-virtual-env nil pyvenv-virtual-env-path-directories nil pyvenv-virtual-env-name nil python-shell-virtualenv-root nil python-shell-virtualenv-path nil)) (defvar pyvenv-workon-history nil "Prompt history for `pyvenv-workon'.") ;;;###autoload (defun pyvenv-workon (name) "Activate a virtual environment from $WORKON_HOME. If the virtual environment NAME is already active, this function does not try to reactivate the environment." (interactive (list (completing-read "Work on: " (pyvenv-virtualenv-list) nil t nil 'pyvenv-workon-history nil nil))) (unless (member name (list "" nil pyvenv-virtual-env-name)) (pyvenv-activate (format "%s/%s" (pyvenv-workon-home) name)))) (defun pyvenv-virtualenv-list (&optional noerror) "Prompt the user for a name in $WORKON_HOME. If NOERROR is set, do not raise an error if WORKON_HOME is not configured." (let ((workon-home (pyvenv-workon-home)) (result nil)) (if (not (file-directory-p workon-home)) (when (not noerror) (error "Can't find a workon home directory, set $WORKON_HOME")) (dolist (name (directory-files workon-home)) (when (or (file-exists-p (format "%s/%s/bin/activate" workon-home name)) (file-exists-p (format "%s/%s/bin/python" workon-home name)) (file-exists-p (format "%s/%s/Scripts/activate.bat" workon-home name)) (file-exists-p (format "%s/%s/python.exe" workon-home name))) (setq result (cons name result)))) (sort result (lambda (a b) (string-lessp (downcase a) (downcase b))))))) (define-widget 'pyvenv-workon 'choice "Select an available virtualenv from virtualenvwrapper." :convert-widget (lambda (widget) (setq widget (widget-copy widget)) (widget-put widget :args (cons '(const :tag "None" nil) (mapcar (lambda (env) (list 'const env)) (pyvenv-virtualenv-list t)))) (widget-types-convert-widget widget)) :prompt-value (lambda (_widget prompt _value _unbound) (let ((name (completing-read prompt (cons "None" (pyvenv-virtualenv-list t)) nil t))) (if (equal name "None") nil name)))) (defvar pyvenv-mode-map (make-sparse-keymap) "The mode keymap for `pyvenv-mode'.") (easy-menu-define pyvenv-menu pyvenv-mode-map "Pyvenv Menu" '("Virtual Envs" :visible pyvenv-mode ("Workon" :help "Activate a virtualenvwrapper environment" :filter (lambda (&optional ignored) (mapcar (lambda (venv) (vector venv `(pyvenv-workon ,venv) :style 'radio :selected `(equal pyvenv-virtual-env-name ,venv))) (pyvenv-virtualenv-list t)))) ["Activate" pyvenv-activate :help "Activate a virtual environment by directory"] ["Deactivate" pyvenv-deactivate :help "Deactivate the current virtual environment" :active pyvenv-virtual-env :suffix pyvenv-virtual-env-name] ["Restart Python Processes" pyvenv-restart-python :help "Restart all Python processes to use the current environment"])) ;;;###autoload (define-minor-mode pyvenv-mode "Global minor mode for pyvenv. Will show the current virtualenv in the mode line, and respect a `pyvenv-workon' setting in files." :global t (cond (pyvenv-mode (add-to-list 'mode-line-misc-info '(pyvenv-mode pyvenv-mode-line-indicator)) (add-hook 'hack-local-variables-hook #'pyvenv-track-virtualenv)) ((not pyvenv-mode) (setq mode-line-misc-info (delete '(pyvenv-mode pyvenv-mode-line-indicator) mode-line-misc-info)) (remove-hook 'hack-local-variables-hook #'pyvenv-track-virtualenv)))) ;;;###autoload (define-minor-mode pyvenv-tracking-mode "Global minor mode to track the current virtualenv. When this mode is active, pyvenv will activate a buffer-specific virtualenv whenever the user switches to a buffer with a buffer-local `pyvenv-workon' or `pyvenv-activate' variable." :global t (if pyvenv-tracking-mode (add-hook 'post-command-hook 'pyvenv-track-virtualenv) (remove-hook 'post-command-hook 'pyvenv-track-virtualenv))) (defun pyvenv-track-virtualenv () "Set a virtualenv as specified for the current buffer. If either `pyvenv-activate' or `pyvenv-workon' are specified, and they specify a virtualenv different from the current one, switch to that virtualenv." (cond (pyvenv-activate (when (and (not (equal (file-name-as-directory pyvenv-activate) pyvenv-virtual-env)) (or (not pyvenv-tracking-ask-before-change) (y-or-n-p (format "Switch to virtualenv %s (currently %s)" pyvenv-activate pyvenv-virtual-env)))) (pyvenv-activate pyvenv-activate))) (pyvenv-workon (when (and (not (equal pyvenv-workon pyvenv-virtual-env-name)) (or (not pyvenv-tracking-ask-before-change) (y-or-n-p (format "Switch to virtualenv %s (currently %s)" pyvenv-workon pyvenv-virtual-env-name)))) (pyvenv-workon pyvenv-workon))))) (defun pyvenv-run-virtualenvwrapper-hook (hook &optional propagate-env &rest args) "Run a virtualenvwrapper hook, and update the environment. This will run a virtualenvwrapper hook and update the local environment accordingly. CAREFUL! If PROPAGATE-ENV is non-nil, this will modify your `process-environment' and `exec-path'." (when (pyvenv-virtualenvwrapper-supported) (with-temp-buffer (let ((tmpfile (make-temp-file "pyvenv-virtualenvwrapper-")) (shell-file-name pyvenv-exec-shell)) (unwind-protect (let ((default-directory (pyvenv-workon-home))) (apply #'call-process pyvenv-virtualenvwrapper-python nil t nil "-m" "virtualenvwrapper.hook_loader" "--script" tmpfile (if (getenv "HOOK_VERBOSE_OPTION") (cons (getenv "HOOK_VERBOSE_OPTION") (cons hook args)) (cons hook args))) (call-process-shell-command (mapconcat 'identity (list (format "%s -c 'import os, json; print(json.dumps(dict(os.environ)))'" pyvenv-virtualenvwrapper-python) (format ". '%s'" tmpfile) (format "%s -c 'import os, json; print(\"\\n=-=-=\"); print(json.dumps(dict(os.environ)))'" pyvenv-virtualenvwrapper-python)) "; ") nil t nil)) (delete-file tmpfile))) (goto-char (point-min)) (when (not (re-search-forward "No module named '?virtualenvwrapper'?" nil t)) (let* ((json-key-type 'string) (env-before (json-read)) (hook-output-start-pos (point)) (hook-output-end-pos (when (re-search-forward "\n=-=-=\n" nil t) (match-beginning 0))) (env-after (when hook-output-end-pos (json-read)))) (when hook-output-end-pos (let ((output (string-trim (buffer-substring hook-output-start-pos hook-output-end-pos)))) (when (> (length output) 0) (with-help-window "*Virtualenvwrapper Hook Output*" (with-current-buffer "*Virtualenvwrapper Hook Output*" (let ((inhibit-read-only t)) (erase-buffer) (insert (format "Output from the virtualenvwrapper hook %s:\n\n" hook) output)))))) (when propagate-env (dolist (binding (pyvenv--env-diff (sort env-before (lambda (x y) (string-lessp (car x) (car y)))) (sort env-after (lambda (x y) (string-lessp (car x) (car y)))))) (setenv (car binding) (cdr binding)) (when (eq (car binding) 'PATH) (let ((new-path-elts (split-string (cdr binding) path-separator))) (setq exec-path new-path-elts) (setq-default eshell-path-env new-path-elts))))))))))) (defun pyvenv--env-diff (env-before env-after) "Calculate diff between ENV-BEFORE alist and ENV-AFTER alist. Both ENV-BEFORE and ENV-AFTER must be sorted alists of (STR . STR)." (let (env-diff) (while (or env-before env-after) (cond ;; K-V are the same, both proceed to the next one. ((equal (car-safe env-before) (car-safe env-after)) (setq env-before (cdr env-before) env-after (cdr env-after))) ;; env-after is missing one element: add (K-before . nil) to diff ((and env-before (or (null env-after) (string-lessp (caar env-before) (caar env-after)))) (setq env-diff (cons (cons (caar env-before) nil) env-diff) env-before (cdr env-before))) ;; Otherwise: add env-after element to the diff, progress env-after, ;; progress env-before only if keys matched. (t (setq env-diff (cons (car env-after) env-diff)) (when (equal (caar env-after) (caar env-before)) (setq env-before (cdr env-before))) (setq env-after (cdr env-after))))) (nreverse env-diff))) ;;;###autoload (defun pyvenv-restart-python () "Restart Python inferior processes." (interactive) (dolist (buf (buffer-list)) (with-current-buffer buf (when (and (eq major-mode 'inferior-python-mode) (get-buffer-process buf)) (let ((cmd (combine-and-quote-strings (process-command (get-buffer-process buf)))) (dedicated (if (string-match "\\[.*\\]$" (buffer-name buf)) t nil)) (show nil)) (delete-process (get-buffer-process buf)) (goto-char (point-max)) (insert "\n\n" "###\n" (format "### Restarting in virtualenv %s (%s)\n" pyvenv-virtual-env-name pyvenv-virtual-env) "###\n" "\n\n") (run-python cmd dedicated show) (goto-char (point-max))))))) (defun pyvenv-hook-dir () "Return the current hook directory. This is usually the value of $VIRTUALENVWRAPPER_HOOK_DIR, but virtualenvwrapper has stopped exporting that variable, so we go back to the default of $WORKON_HOME or even just ~/.virtualenvs/." (or (getenv "VIRTUALENVWRAPPER_HOOK_DIR") (pyvenv-workon-home))) (defun pyvenv-workon-home () "Return the current workon home. This is the value of $WORKON_HOME or ~/.virtualenvs." (or (getenv "WORKON_HOME") (expand-file-name "~/.virtualenvs"))) (defun pyvenv-virtualenvwrapper-supported () "Return true iff virtualenvwrapper is supported. Right now, this just checks if WORKON_HOME is set." (getenv "WORKON_HOME")) (defun pyvenv--virtual-env-bin-dirs (virtual-env) (let ((virtual-env (if (string= "/" (directory-file-name virtual-env)) "" (directory-file-name virtual-env)))) (append ;; Unix (when (file-exists-p (format "%s/bin" virtual-env)) (list (format "%s/bin" virtual-env))) ;; Windows (when (file-exists-p (format "%s/Scripts" virtual-env)) (list (format "%s/Scripts" virtual-env) ;; Apparently, some virtualenv ;; versions on windows put the ;; python.exe in the virtualenv root ;; for some reason? virtual-env))))) (defun pyvenv--replace-once-destructive (list oldvalue newvalue) "Replace one element equal to OLDVALUE with NEWVALUE values in LIST." (let ((cur-elt list)) (while (and cur-elt (not (equal oldvalue (car cur-elt)))) (setq cur-elt (cdr cur-elt))) (when cur-elt (setcar cur-elt newvalue)))) (defun pyvenv--remove-many-once (values-to-remove list) "Return a copy of LIST with each element from VALUES-TO-REMOVE removed once." ;; Non-interned symbol is not eq to anything but itself. (let ((values-to-remove (copy-sequence values-to-remove)) (sentinel (make-symbol "sentinel"))) (delq sentinel (mapcar (lambda (x) (if (pyvenv--replace-once-destructive values-to-remove x sentinel) sentinel x)) list)))) (defun pyvenv--prepend-to-pathsep-string (values-to-prepend str) "Prepend values from VALUES-TO-PREPEND list to path-delimited STR." (mapconcat 'identity (append values-to-prepend (split-string str path-separator)) path-separator)) (defun pyvenv--remove-from-pathsep-string (values-to-remove str) "Remove all values from VALUES-TO-REMOVE list from path-delimited STR." (mapconcat 'identity (pyvenv--remove-many-once values-to-remove (split-string str path-separator)) path-separator)) (defun pyvenv--add-dirs-to-PATH (dirs-to-add) "Add DIRS-TO-ADD to different variables related to execution paths." (let* ((new-eshell-path-env (pyvenv--prepend-to-pathsep-string dirs-to-add (default-value 'eshell-path-env))) (new-path-envvar (pyvenv--prepend-to-pathsep-string dirs-to-add (getenv "PATH")))) (setq exec-path (append dirs-to-add exec-path)) (setq-default eshell-path-env new-eshell-path-env) (setenv "PATH" new-path-envvar))) (defun pyvenv--remove-dirs-from-PATH (dirs-to-remove) "Remove DIRS-TO-REMOVE from different variables related to execution paths." (let* ((new-eshell-path-env (pyvenv--remove-from-pathsep-string dirs-to-remove (default-value 'eshell-path-env))) (new-path-envvar (pyvenv--remove-from-pathsep-string dirs-to-remove (getenv "PATH")))) (setq exec-path (pyvenv--remove-many-once dirs-to-remove exec-path)) (setq-default eshell-path-env new-eshell-path-env) (setenv "PATH" new-path-envvar))) ;;; Compatibility (when (not (fboundp 'file-name-base)) ;; Emacs 24.3 (defun file-name-base (&optional filename) "Return the base name of the FILENAME: no directory, no extension. FILENAME defaults to `buffer-file-name'." (file-name-sans-extension (file-name-nondirectory (or filename (buffer-file-name))))) ) (when (not (boundp 'mode-line-misc-info)) (defvar mode-line-misc-info nil "Compatibility variable for 24.3+") (let ((line mode-line-format)) (while line (when (eq 'which-func-mode (car-safe (car-safe (cdr line)))) (setcdr line (cons 'mode-line-misc-format (cdr line))) (setq line (cdr line))) (setq line (cdr line))))) (provide 'pyvenv) ;;; pyvenv.el ends here pyvenv-el-1.21+git20211014.31ea715/scripts/000077500000000000000000000000001450567470300174435ustar00rootroot00000000000000pyvenv-el-1.21+git20211014.31ea715/scripts/release000077500000000000000000000002461450567470300210130ustar00rootroot00000000000000#!/bin/bash set -e cd "$(dirname "$0")/.." main() { run bumpversion minor run git push run git push --tags } run() { echo "\$ $*" "$@" } main pyvenv-el-1.21+git20211014.31ea715/test/000077500000000000000000000000001450567470300167335ustar00rootroot00000000000000pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-activate-test.el000066400000000000000000000026241450567470300233630ustar00rootroot00000000000000(ert-deftest pyvenv-activate () "`pyvenv-activate' should set the correct variables." (with-temp-virtualenv tmpdir (let* ((process-environment process-environment) (exec-path exec-path) (pyvenv-virtual-env nil) (pyvenv-virtual-env-name nil) (pyvenv-old-process-environment nil) (pyvenv-old-exec-path nil) (pre-activate-venv nil) (post-activate-venv nil) (pyvenv-pre-activate-hooks (list (lambda () (setq pre-activate-venv pyvenv-virtual-env)))) (pyvenv-post-activate-hooks (list (lambda () (setq post-activate-venv pyvenv-virtual-env))))) (pyvenv-activate tmpdir) (should (f-equal? pre-activate-venv tmpdir)) (should (f-equal? post-activate-venv tmpdir)) (should (f-equal? pyvenv-virtual-env tmpdir)) (should (equal pyvenv-virtual-env-name (file-name-base tmpdir))) (should (equal python-shell-virtualenv-path tmpdir)) (should (equal python-shell-virtualenv-root tmpdir)) (should (equal (getenv "VIRTUAL_ENV") tmpdir)) (should (string-match (format "^%s/bin" (regexp-quote tmpdir)) (getenv "PATH"))) (should (equal (getenv "PYTHONHOME") nil)) (should (member (format "%s/bin" tmpdir) exec-path))))) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-deactivate-test.el000066400000000000000000000034571450567470300237010ustar00rootroot00000000000000(ert-deftest pyvenv-deactivate () "Should set variables back to the original values." (let* ((process-environment process-environment) (exec-path exec-path) (orig-process-environment process-environment) (orig-exec-path exec-path) (pre-deactivate-venv nil) (post-deactivate-venv nil) (pyvenv-pre-deactivate-hooks (list (lambda () (setq pre-deactivate-venv pyvenv-virtual-env)))) (pyvenv-post-deactivate-hooks (list (lambda () (setq post-deactivate-venv pyvenv-virtual-env))))) (with-temp-virtualenv venv1 (pyvenv-activate venv1) (pyvenv-deactivate) (should (f-same? pre-deactivate-venv venv1)) (should (f-same? post-deactivate-venv venv1)) (should (equal (canonicalize-environment process-environment) (canonicalize-environment orig-process-environment))) (should (equal exec-path orig-exec-path)) (should (equal pyvenv-virtual-env nil)) (should (equal pyvenv-virtual-env-name nil)) (with-temp-virtualenv venv2 ;; Should retain the originals, too. (pyvenv-activate venv1) (pyvenv-activate venv2) (pyvenv-deactivate) ;; Called for both, but the last one was for the second (should (f-same? pre-deactivate-venv venv2)) (should (f-same? post-deactivate-venv venv2)) (should (equal (canonicalize-environment process-environment) (canonicalize-environment orig-process-environment))) (should (equal exec-path orig-exec-path)) (should (equal pyvenv-virtual-env nil)) (should (equal pyvenv-virtual-env-name nil)) (should (equal python-shell-virtualenv-root nil)) (should (equal python-shell-virtualenv-path nil)))))) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-env-diff-test.el000066400000000000000000000013151450567470300232550ustar00rootroot00000000000000(ert-deftest pyvenv--env-diff () ;; This test has a simple convention: lowercase strings are old values, ;; uppercase strings are new values. (should (equal (pyvenv--env-diff '() '()) '())) (should (equal (pyvenv--env-diff '((a . "a")) '()) '((a . nil)))) (should (equal (pyvenv--env-diff '() '((a . "A"))) '((a . "A")))) (should (equal (pyvenv--env-diff '((a . "a")) '((b . "B"))) '((a . nil) (b . "B")))) (should (equal (pyvenv--env-diff '((c . "c")) '((b . "B"))) '((b . "B") (c . nil)))) (should (equal (pyvenv--env-diff '((b . "b")) '((a . "A") (c . "C"))) '((a . "A") (b . nil) (c . "C"))))) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-hook-dir-test.el000066400000000000000000000016101450567470300232710ustar00rootroot00000000000000(ert-deftest pyvenv-hook-dir () ;; Should return VIRTUALENVWRAPPER_HOOK_DIR (let ((process-environment (cons "VIRTUALENVWRAPPER_HOOK_DIR=/hook_dir" process-environment))) (should (equal (pyvenv-hook-dir) "/hook_dir"))) ;; Else, should return WORKON_HOME (let ((process-environment (append '("VIRTUALENVWRAPPER_HOOK_DIR" "WORKON_HOME=/workon_home") process-environment))) (should (equal (pyvenv-hook-dir) "/workon_home"))) ;; Else, should return ~/.virtualenvs (let ((process-environment (append '("VIRTUALENVWRAPPER_HOOK_DIR" "WORKON_HOME") process-environment))) (should (equal (pyvenv-hook-dir) (expand-file-name "~/.virtualenvs")))) ) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-mode-test.el000066400000000000000000000012271450567470300225050ustar00rootroot00000000000000(ert-deftest pyvenv-mode-should-add-functions () (with-temp-buffer (pyvenv-mode 1) (should pyvenv-mode) (should (member '(pyvenv-mode pyvenv-mode-line-indicator) mode-line-misc-info)) (should (memq #'pyvenv-track-virtualenv hack-local-variables-hook)))) (ert-deftest pyvenv-mode-should-remove-functions () (with-temp-buffer (pyvenv-mode 1) (pyvenv-mode -1) (should-not pyvenv-mode) (should-not (memq '(pyvenv-mode pyvenv-mode-line-indicator) mode-line-misc-info)) (should-not (memq #'pyvenv-track-virtualenv hack-local-variables-hook)))) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-track-virtualenv.el000066400000000000000000000043561450567470300241130ustar00rootroot00000000000000(ert-deftest pyvenv-track-virtualenv-should-activate-venv-if-none-set () (with-temp-buffer (mocker-let ((pyvenv-activate (env) ((:input '("/test/path"))))) (let ((pyvenv-activate "/test/path") (pyvenv-virtual-env nil)) (pyvenv-track-virtualenv))))) (ert-deftest pyvenv-track-virtualenv-should-ask-if-activate-different-venv () (with-temp-buffer (mocker-let ((pyvenv-activate (env) ((:input '("/test/path")))) (y-or-n-p (arg) ((:input '("Switch to virtual env /test/path (currently /other/path)? ") :output t)))) (let ((pyvenv-activate "/test/path") (pyvenv-virtual-env "/other/path")) (pyvenv-track-virtualenv))))) (ert-deftest pyvenv-track-virtualenv-should-do-nothing-if-activate-same-venv () (with-temp-buffer (let ((pyvenv-activate "/test/path") ;; activate takes precedence over workon (pyvenv-workon "foo") (pyvenv-virtual-env "/test/path")) (pyvenv-track-virtualenv) (should (equal pyvenv-virtual-env "/test/path"))))) (ert-deftest pyvenv-track-virtualenv-should-workon-venv-if-none-set () (with-temp-buffer (mocker-let ((pyvenv-workon (env) ((:input '("test-venv"))))) (let ((pyvenv-workon "test-venv") (pyvenv-virtual-env nil)) (pyvenv-track-virtualenv))))) (ert-deftest pyvenv-track-virtualenv-should-ask-if-workon-different-venv () (with-temp-buffer (mocker-let ((pyvenv-workon (env) ((:input '("test-venv")))) (y-or-n-p (arg) ((:input '("Switch to virtual env test-venv (currently other-venv)? ") :output t)))) (let ((pyvenv-workon "test-venv") (pyvenv-virtual-env "/some/path/other-venv") (pyvenv-virtual-env-name "other-venv")) (pyvenv-track-virtualenv))))) (ert-deftest pyvenv-track-virtualenv-should-do-nothing-if-workon-same-venv () (with-temp-buffer (let ((pyvenv-workon "test-venv") (pyvenv-virtual-env-name "test-venv")) (pyvenv-track-virtualenv) (should (equal pyvenv-virtual-env-name "test-venv"))))) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-virtualenv-list-test.el000066400000000000000000000020621450567470300247270ustar00rootroot00000000000000(ert-deftest pyvenv-virtualenv-list () "Ensure all correct virtualenvs are returned" (with-temp-dir workon-home (let ((process-environment process-environment)) (setq process-environment (cons (format "WORKON_HOME=%s/does-not-exist" workon-home) process-environment)) (should-error (pyvenv-virtualenv-list)) (should (null (pyvenv-virtualenv-list t))) (setq process-environment (cons (format "WORKON_HOME=%s" workon-home) (cdr process-environment))) (should (equal (pyvenv-virtualenv-list) nil)) (make-directory (format "%s/no-venv-dir" workon-home)) (write-region "" nil (format "%s/no-venv-file" workon-home)) (dolist (name '("venv-a" "venv-B" "venv-C")) (make-directory (format "%s/%s" workon-home name)) (make-directory (format "%s/%s/bin" workon-home name)) (write-region "" nil (format "%s/%s/bin/activate" workon-home name))) (should (equal (pyvenv-virtualenv-list) '("venv-a" "venv-B" "venv-C")))))) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-workon-home-test.el000066400000000000000000000010031450567470300240160ustar00rootroot00000000000000(ert-deftest pyvenv-hook-dir () ;; Else, should return WORKON_HOME (let ((process-environment (cons "WORKON_HOME=/workon_home" process-environment))) (should (equal (pyvenv-workon-home) "/workon_home"))) ;; Else, should return ~/.virtualenvs (let ((process-environment (cons "WORKON_HOME" process-environment))) (should (equal (pyvenv-workon-home) (expand-file-name "~/.virtualenvs")))) ) pyvenv-el-1.21+git20211014.31ea715/test/pyvenv-workon-test.el000066400000000000000000000016051450567470300231000ustar00rootroot00000000000000(ert-deftest pyvenv-workon () ;; Should expand the virtualenv directory then call activate. (mocker-let ((pyvenv-activate (dir) ((:input-matcher (lambda (env) (string-match "/test-env$" env)) :output t)))) (should (pyvenv-workon "test-env"))) ;; Should not activate anything when the user just hits RET. (mocker-let ((pyvenv-activate (dir) ((:min-occur 0 :max-occur 0)))) (should-not (pyvenv-workon ""))) ;; Some completion frameworks can return nil for the default, see ;; https://github.com/jorgenschaefer/elpy/issues/144 (mocker-let ((pyvenv-activate (dir) ((:min-occur 0 :max-occur 0)))) (should-not (pyvenv-workon nil)))) pyvenv-el-1.21+git20211014.31ea715/test/test-helper.el000066400000000000000000000023411450567470300215110ustar00rootroot00000000000000(require 'f) (add-to-list 'load-path (f-parent (f-dirname (f-this-file)))) (require 'pyvenv) (require 'mocker) ;; Fixing a bug in dflet where it would not work in 24.3.1 for some ;; reason. (when (version= emacs-version "24.3.1") (require 'cl)) (defmacro with-temp-dir (name &rest body) (let ((var (make-symbol "temp-dir"))) `(let* ((,var (make-temp-file "pyvenv-test-" t)) (,name ,var)) (unwind-protect (progn ,@body) (delete-directory ,var t))))) (put 'with-temp-dir 'lisp-indent-function 'defun) (defmacro with-temp-virtualenv (name &rest body) `(with-temp-dir ,name (make-directory (concat ,name "/bin")) (write-region "" nil (concat ,name "/bin/activate")) ,@body)) (put 'with-temp-virtualenv 'lisp-indent-function 'defun) (defun canonicalize-environment (process-environment-list) "Prepare PROCESS-ENVIRONMENT-LIST variable for comparison." (let (result) ;; Dedupe by var name. (mapc (lambda (x) (cl-pushnew (split-string x "=") result :key 'car :test 'equal)) process-environment) ;; Delete vars that were unset, and sort the result. (sort (cl-delete-if-not 'cdr result) (lambda (x y) (string-lessp (car x) (car y))))))