cca4043238421ae8e018720326d5357027f27cf8

Author
Marc Cornellà <marc@mcornella.com>
Committer
GitHub <noreply@github.com>
Date

Message

feat(python): support multiple venvs via `$PYTHON_VENV_NAMES` (#12932)

Diff

  1diff --git a/plugins/python/README.md b/plugins/python/README.md
  2index 8014992de3239d43c1b7a272e802f49dabac67d5..490cf88f163d84f60779bf4326cf1067b2a45594 100644
  3--- a/plugins/python/README.md
  4+++ b/plugins/python/README.md
  5@@ -24,16 +24,45 @@ plugins=(... python)
  6 The plugin provides three utilities to manage Python 3.3+ [venv](https://docs.python.org/3/library/venv.html)
  7 virtual environments:
  8 
  9-- `mkv [name]`: make a new virtual environment called `name` (default: if set `$PYTHON_VENV_NAME`, else
 10-  `venv`) in the current directory.
 11+- `mkv [name]`: make a new virtual environment called `name` in the current directory.
 12+  **Default**: `$PYTHON_VENV_NAME` if set, otherwise `venv`.
 13 
 14-- `vrun [name]`: Activate the virtual environment called `name` (default: if set `$PYTHON_VENV_NAME`, else
 15-  `venv`) in the current directory.
 16+- `vrun [name]`: activate the virtual environment called `name` in the current directory.
 17+  **Default**: the first existing in `$PYTHON_VENV_NAMES`.
 18 
 19-- `auto_vrun`: Automatically activate the venv virtual environment when entering a directory containing
 20+- `auto_vrun`: automatically activate the venv virtual environment when entering a directory containing
 21   `<venv-name>/bin/activate`, and automatically deactivate it when navigating out of it (keeps venv activated
 22   in subdirectories).
 23-  - To enable the feature, set `export PYTHON_AUTO_VRUN=true` before sourcing oh-my-zsh.
 24-  - Plugin activates first virtual environment in lexicographic order whose name begins with `<venv-name>`.
 25+  - To enable the feature, set `PYTHON_AUTO_VRUN=true` before sourcing oh-my-zsh.
 26+  - The plugin activates the first existing virtual environment, in order, appearing in `$PYTON_VENV_NAMES`.
 27     The default virtual environment name is `venv`. To use a different name, set
 28-    `export PYTHON_VENV_NAME=<venv-name>`. For example: `export PYTHON_VENV_NAME=".venv"`
 29+    `PYTHON_VENV_NAME=<venv-name>`. For example: `PYTHON_VENV_NAME=".venv"`
 30+
 31+### Settings
 32+
 33+You can set these variables in your `.zshrc` file, before Oh My Zsh is sourced.
 34+For example:
 35+
 36+```sh
 37+PYTHON_VENV_NAME=".venv"
 38+PYTHON_VENV_NAMES=($PYTHON_VENV_NAME venv)
 39+...
 40+plugins=(... python)
 41+source "$ZSH/oh-my-zsh.sh"
 42+```
 43+
 44+
 45+## `$PYTHON_VENV_NAME`
 46+
 47+**Default**: `venv`.
 48+
 49+Preferred name for virtual environments, for example when creating via `mkv`.
 50+
 51+## `$PYTHON_VENV_NAMES`
 52+
 53+**Default**: `$PYTHON_VENV_NAME venv .venv`.
 54+
 55+Array of virtual environment names to be checked, in order, by `vrun` and `auto_vrun`.
 56+This means these functions will load the first existing virtual environment in this list.
 57+Duplicate names are ignored.
 58+
 59diff --git a/plugins/python/python.plugin.zsh b/plugins/python/python.plugin.zsh
 60index 63733e1de72f0298c7d7c5a0165cd49439e8e929..2b139ddf0c79947452e07ed8d18acd7c176582d1 100644
 61--- a/plugins/python/python.plugin.zsh
 62+++ b/plugins/python/python.plugin.zsh
 63@@ -47,12 +47,29 @@ alias pygrep='grep -nr --include="*.py"'
 64 alias pyserver="python3 -m http.server"
 65 
 66 
 67-## venv utilities
 68+## venv settings
 69 : ${PYTHON_VENV_NAME:=venv}
 70 
 71+# Array of possible virtual environment names to look for, in order
 72+# -U for removing duplicates
 73+typeset -gaU PYTHON_VENV_NAMES
 74+[[ -n "$PYTHON_VENV_NAMES" ]] || PYTHON_VENV_NAMES=($PYTHON_VENV_NAME venv .venv)
 75+
 76 # Activate a the python virtual environment specified.
 77-# If none specified, use $PYTHON_VENV_NAME, else 'venv'.
 78+# If none specified, use the first existing in $PYTHON_VENV_NAMES.
 79 function vrun() {
 80+  if [[ -z "$1" ]]; then
 81+    local name
 82+    for name in $PYTHON_VENV_NAMES; do
 83+      local venvpath="${name:P}"
 84+      if [[ -d "$venvpath" ]]; then
 85+        vrun "$name"
 86+        return $?
 87+      fi
 88+    done
 89+    echo >&2 "Error: no virtual environment found in current directory"
 90+  fi
 91+
 92   local name="${1:-$PYTHON_VENV_NAME}"
 93   local venvpath="${name:P}"
 94 
 95@@ -91,10 +108,11 @@ if [[ "$PYTHON_AUTO_VRUN" == "true" ]]; then
 96     fi
 97 
 98     if [[ $PWD != ${VIRTUAL_ENV:h} ]]; then
 99-      for _file in "${PYTHON_VENV_NAME}"*/bin/activate(N.); do
100+      local file
101+      for file in "${^PYTHON_VENV_NAMES[@]}"/bin/activate(N.); do
102         # make sure we're not in a venv already
103         (( $+functions[deactivate] )) && deactivate > /dev/null 2>&1
104-        source $_file > /dev/null 2>&1
105+        source $file > /dev/null 2>&1
106         break
107       done
108     fi