Как автоматически активировать virtualenvs при переходе в каталог
У меня есть куча проектов в моем ~/Documents
, Я работаю почти исключительно на Python, так что это в основном все проекты Python. Каждый, например ~/Documents/foo
имеет свой собственный virtualenv, ~/Documents/foo/venv
(они всегда называются venv). Всякий раз, когда я переключаюсь между проектами, то есть ~10 раз в день, я делаю
deactivate
cd ..
cd foo
source venv/bin/activate
Я дошел до того, что мне надоело печатать deactivate
а также source venv/bin/activate
, Я ищу способ просто cd ../foo
и обработать virtualenv для меня.
Я знаком с VirtualEnvWrapper, который, на мой взгляд, немного жесток. Кажется, что он перемещает все ваши virtualenvs куда-то еще и добавляет немного больше сложности, чем удаляет, насколько я могу судить. (Особые мнения приветствуются!)
Я не слишком знаком со сценариями оболочки. Если вы можете порекомендовать скрипт для низких эксплуатационных расходов, чтобы добавить в мой
~/.zshrc
этого достаточно, этого было бы более чем достаточно, но из-за быстрого поиска, я не нашел такого сценария.Я
zsh
/oh-my-zsh
пользователь.oh-my-zsh
не похоже на плагин для этого. Лучшим ответом на этот вопрос будет кто-тоoh-my-zsh
плагин, который делает это. (Что я мог бы сделать, если ответы здесь тусклые.
23 ответа
Положите что-то вроде этого в вашем.zshrc
function cd() {
if [[ -d ./venv ]] ; then
deactivate
fi
builtin cd $1
if [[ -d ./venv ]] ; then
. ./venv/bin/activate
fi
}
Изменить: как отмечено в комментариях cd
-включение в подпапку текущей виртуальной среды ENV приведет к ее деактивации. Одна идея может состоять в том, чтобы деактивировать текущий env, только если cd
в новый, как
function cd() {
builtin cd $1
if [[ -n "$VIRTUAL_ENV" && -d ./venv ]] ; then
deactivate
. ./venv/bin/activate
fi
}
это все еще можно улучшить, возможно, превратив его в "команду приглашения" или попытавшись сопоставить префикс в именах папок, чтобы проверить, есть ли где-то в пути виртуальный env, но мой shell-fu не достаточно хорош.
Добавьте следующее в ваш.bashrc или.zshrc
function cd() {
builtin cd $@
if [[ -z "$VIRTUAL_ENV" ]] ; then
## If env folder is found then activate the vitualenv
if [[ -d ./env ]] ; then
source ./env/bin/activate
fi
else
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate
parentdir="$(dirname "$VIRTUAL_ENV")"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
deactivate
fi
fi
}
Этот код не деактивирует virtualenv, даже если кто-то перейдет в подпапку. Вдохновлен ответами @agnul и @Gilles.
Кроме того, для дополнительной безопасности, пожалуйста, обратите внимание на direnv.
Вам следует попробовать что-то вроде autoenv, если не direnv.
Первый считается "легковесным", а второй - "просто более качественным программным обеспечением", который соответственно слушает каждого автора и рассказывает о проекте другого. Таким образом, они кажутся мне довольно хорошими вариантами, чтобы попробовать оба!
Во всяком случае, оба были протестированы на zsh
снаряды. Особенно,autoenv
действительно прост в использовании, после его установки:
$ git clone git://github.com/inishchith/autoenv.git ~/.autoenv
$ echo 'source ~/.autoenv/activate.sh' >> ~/.bashrc
просто "следуй за белым кроликом " и попробуйте, например,
$ mkdir project
$ echo "echo 'whoa'" > project/.env
$ cd project
whoa
"Если каталог содержит .env
файл, он будет автоматически выполнен, когда вы cd
внутрь. При включении (установитьAUTOENV_ENABLE_LEAVE
в ненулевую строку), если каталог содержит .env.leave
файл, он будет автоматически выполнен, когда вы его покинете ".
Загляните на https://github.com/inishchith/autoenv для получения более подробных инструкций!...
Вместо написания собственного скрипта вы можете использовать direnv. Это не специфичное для zsh решение (для этого вы можете попробовать zsh-autoenv), но оно хорошо поддерживается и легко в использовании с zsh. После того, как вы установили его, вы хотите поставить eval "$(direnv hook zsh)"
в конце вашего .zshrc
, На этом этапе вы можете сделать:
$ source ~/.zshrc
$ cd foo
$ echo "layout python" > .envrc
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
$ direnv allow
direnv: loading .envrc
direnv: export +VIRTUAL_ENV ~PATH
Теперь вы должны быть в своем виртуальности. Вы можете проверить, запустив pip freeze
чтобы увидеть, что ваши конкретные пакеты virtualenv установлены. Деактивировать
$ cd ..
direnv: unloading
По далеко самый простой вариант (в 2019+) является добавлениеvirtualenvwrapper
в ваш ~/.zshrc
plugins
Например:
plugins=(
git pip python brew virtualenvwrapper
)
Для всех, кто использует (или рассматривает возможность использования) pyenv, это может быть очень удобно достигнуто с помощью плагина pyenv-virtualenv, как описано здесь .
Обычно вы просто добавляете
.python-version
файл в каталог, в котором указано имя virtualenv.
Это решение только для zsh.
Это улучшение по сравнению с ответом daveruinseverything, которое является улучшением по сравнению с ответом MS_.
Мы используем
precmd
перехватить вместо перезаписи
cd
.
Мы добавили еще одну дополнительную функцию. Предположим, что структура каталогов
├── .venv
│ ├── bin
│ │ └── activate
├── subdir
│ ├── subdir1
│ │ ├── subdir2
│ │ │ └── test2.txt
│ │ └── test1.txt
│ └── test.txt
└── testing.py
Если вы сейчас откроете новый терминал в subdir2 или напрямую перейдете в subdir2 из другого места, он активирует venv.
Решение такое:
autoload -Uz add-zsh-hook
add-zsh-hook precmd automatically_activate_python_venv
function automatically_activate_python_env() {
if [[ -z $VIRTUAL_ENV ]] ; then
activate_venv
else
parentdir="$(dirname ${VIRTUAL_ENV})"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
deactivate
activate_venv
fi
fi
}
function activate_venv() {
local d n
d=$PWD
until false
do
if [[ -f $d/.venv/bin/activate ]] ; then
source $d/.venv/bin/activate
break
fi
d=${d%/*}
# d="$(dirname "$d")"
[[ $d = *\/* ]] || break
done
}
Для потомков: я использовал решение @MS_, но столкнулся с проблемой, когда cd
прямой переход из одного проекта в другой деактивирует старый virtualenv, но не активирует новый. Это слегка измененная версия этого решения, которое решает эту проблему:
# auto activate virtualenv
# Modified solution based on https://stackru.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function cd() {
builtin cd "$@"
## Default path to virtualenv in your projects
DEFAULT_ENV_PATH="./env"
## If env folder is found then activate the vitualenv
function activate_venv() {
if [[ -f "${DEFAULT_ENV_PATH}/bin/activate" ]] ; then
source "${DEFAULT_ENV_PATH}/bin/activate"
echo "Activating ${VIRTUAL_ENV}"
fi
}
if [[ -z "$VIRTUAL_ENV" ]] ; then
activate_venv
else
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate then run a new env folder check
parentdir="$(dirname ${VIRTUAL_ENV})"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
echo "Deactivating ${VIRTUAL_ENV}"
deactivate
activate_venv
fi
fi
}
Это решение без cd'ing, с zsh, установленным наsetop auto_cd
w сможет менять каталоги без компакт-диска, просто введите имя каталога и нажмите Enter. это anhence вышеуказанного решения:
# auto activate virtualenv
# Modified solution based on https://stackru.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function auto_active_env() {
## Default path to virtualenv in your projects
DEFAULT_ENV_PATH="./env"
## If env folder is found then activate the vitualenv
function activate_venv() {
if [[ -f "${DEFAULT_ENV_PATH}/bin/activate" ]] ; then
source "${DEFAULT_ENV_PATH}/bin/activate"
echo "Activating ${VIRTUAL_ENV}"
fi
}
if [[ -z "$VIRTUAL_ENV" ]] ; then
activate_venv
else
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate then run a new env folder check
parentdir="$(dirname ${VIRTUAL_ENV})"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
echo "Deactivating ${VIRTUAL_ENV}"
deactivate
activate_venv
fi
fi
}
chpwd_functions=(${chpwd_functions[@]} "auto_active_env")
Аналогично ответу Джейка, но поддерживает
cd
переход от одного виртуального окружения к другому. В этом случае он деактивирует старый virtualenv, а затем активирует новый.
function cd() {
builtin cd "$@"
if [[ ! -z "$VIRTUAL_ENV" ]] ; then
# If the current directory is not contained
# within the venv parent directory -> deactivate the venv.
cur_dir=$(pwd -P)
venv_dir="$(dirname "$VIRTUAL_ENV")"
if [[ "$cur_dir"/ != "$venv_dir"/* ]] ; then
deactivate
fi
fi
if [[ -z "$VIRTUAL_ENV" ]] ; then
# If config file is found -> activate the vitual environment
venv_cfg_filepath=$(find . -maxdepth 2 -type f -name 'pyvenv.cfg' 2> /dev/null)
if [[ -z "$venv_cfg_filepath" ]]; then
return # no config file found
fi
venv_filepath=$(cut -d '/' -f -2 <<< ${venv_cfg_filepath})
if [[ -d "$venv_filepath" ]] ; then
source "${venv_filepath}"/bin/activate
fi
fi
}
Для такого разработчика Python, как я, я использую этот плагин для создания, активации виртуальных сред Python при входе в проект Python, он также деактивируется после
cd
в другой каталог.
В настоящее время есть небольшая ошибка, из-за которой ваша тема ZSH вернется к значениям по умолчанию после деактивации, и здесь есть исправление.
Я попробовал direnv, как предлагали другие, но нашел его слишком самоуверенным и не совсем то, что я хотел.
Приведенное ниже решение предназначено только для пользователей рыбных раковин . Кроме того, он предполагаетpyproject.toml
файл и стандартная библиотекаvenv
, но это можно легко изменить.
Оболочка fish имеет концепцию обработчиков событий , поэтому вы можете легко определить функцию, которая запускается всякий раз, когда запускается «событие» (сигналы Unix, изменение переменных среды и т. д.). См . этот пост в блоге для краткого ознакомления.
Добавьте следующее в свой~/.config/fish/config.fish
(и изменить при необходимости):
function venv_activate --on-variable PWD
if test ! -e pyproject.toml
if test -n "$VIRTUAL_ENV"
deactivate
end
return
end
# echo "Found pyproject.toml"
if test ! -d .venv
# echo "Creating $(python -V) venv"
python -m venv .venv --prompt (basename (pwd))
end
source .venv/bin/activate.fish
end
В качестве примечания вышеизложенное прекрасно работает сpyenv
х.python-version
файлы также.
Предупреждение о саморекламе!
Если вы используете oh-my-zsh, я разветвил и значительно улучшил (по моему мнению) плагин, который работает как для bash, так и для zsh, и включил инструкции по установке с помощью oh-my-zsh.
Вот (еще) еще одно решение для автоматической активации виртуальной среды; он основан на ряде ответов, уже опубликованных здесь.
Это будет работать для любого имени или каталога виртуальной среды (не только./env
, ./venv
, так далее.). Также поддерживает подкаталоги, а такжеcd
-введение в символические ссылки папок виртуального окружения (родительских).
Этот код ищет pyvenv.cfg
файл вместо конкретного именованного каталога. Если он находится в подкаталоге текущей папки, среда активируется автоматически. Попав в виртуальную среду, это состояние сохраняется до тех пор, пока вы не выйдете из родительского каталога виртуальной среды, после чего среда будет деактивирована.
Поместите это в свой .bashrc
или .bash_profile
.
function cd() {
builtin cd "$@"
if [[ -z "$VIRTUAL_ENV" ]] ; then
# If config file is found -> activate the vitual environment
venv_cfg_filepath=$(find . -maxdepth 2 -type f -name 'pyvenv.cfg' 2> /dev/null)
if [[ -z "$venv_cfg_filepath" ]]; then
return # no config file found
fi
venv_filepath=$(cut -d '/' -f -2 <<< ${venv_cfg_filepath})
if [[ -d "$venv_filepath" ]] ; then
source "${venv_filepath}"/bin/activate
fi
else
# If the current directory is not contained
# within the venv parent directory -> deactivate the venv.
cur_dir=$(pwd -P)
venv_dir="$(dirname "$VIRTUAL_ENV")"
if [[ "$cur_dir"/ != "$venv_dir"/* ]] ; then
deactivate
fi
fi
}
Лично я считаю, что это улучшение многих решений здесь, поскольку оно должно работать в любой виртуальной среде.
Вот альтернатива, которая устанавливает переменную env при переходе в каталог virtualenv и проверяет, является ли активный подкаталог дочерним каталогом указанного виртуального окружения.
Это также деактивируется при выходе или переходе в другой каталог.
Это предполагает, что вы используете Pyenv для управления установками Python, однако вы можете изменить
function cd() {
builtin cd "$@"
if [[ -f ./pyvenv.cfg ]] ; then
export VENV_CURRENT=$PWD
source ./bin/activate
else
if [[ $(env | fgrep VENV_CURRENT) ]]; then
if ! [[ $(pwd | fgrep $VENV_CURRENT) ]]; then
unset VENV_CURRENT
deactivate
fi
fi
fi
}
Вы можете использовать функцию ловушки zsh, которая запускается всякий раз, когда вы меняете каталоги. Например, вы можете добавить это в свой файл ~/.zshrc:
# Define a function to activate/deactivate virtualenvs based on the current directory
function venv_cd() {
# Check if the current directory has a venv subdirectory
if [[ -d venv ]]; then
# If yes, activate it if it's not already active
if [[ "$VIRTUAL_ENV" != "$PWD/venv" ]]; then
source venv/bin/activate
fi
else
# If no, deactivate the current virtualenv if any
if [[ -n "$VIRTUAL_ENV" ]]; then
deactivate
fi
fi
}
Добавьте функцию в хук chpwd, который запускается после каждого cd.
add-zsh-hook chpwd venv_cd
При желании запустите функцию один раз в начале сеанса.
venv_cd
Это должно автоматически активировать virtualenv в текущем каталоге, если он существует, или деактивировать его, если вы перейдете в каталог без такового.
Я использовал direnv в прошлом, как упоминали другие. Lyft использует активатор именно для этого сценария .
После создания venv его необходимо активировать (добавить в $PATH). Мы используем активатор, чтобы автоматически активировать venv каждый раз, когда пользователь входит в каталог службы, и деактивировать его при выходе.
Это мое решение, которое:
- проверяет, активен ли он в данный момент
venv
и ничего не делать в этом случае - если есть
venv
папку, деактивировать активную, если она есть - активировать новый
venv
независимо от того, был ли старый или нет.
В моем bash_aliases
:
function cd() {
builtin cd "$@"
if [ $(dirname "$VIRTUAL_ENV") == $(pwd) ] ; then
# Already at the active virtual env
return
fi
if [[ -d ./venv ]] ; then
if type deactivate > /dev/null 2>&1 ; then
printf "Deactivating virtualenv %s\n" "$VIRTUAL_ENV"
deactivate
fi
source ./venv/bin/activate
printf "Setting up virtualenv %s\n" "$VIRTUAL_ENV"
fi
}
Это мое решение:
- Если VIRTUAL_ENV не установлен, тогда:
- Проверьте, находимся ли мы в виртуальном окружении
- Если да, то активируйте его
- Иначе (определено VIRTUAL_ENV), убедитесь, что текущая папка начинается с $VIRTUAL_ENV (удаление
/venv
часть) и убедитесь, что команда деактивировать существует- Деактивировать среду
Это сценарий:
function cd() {
builtin cd $1
if [[ -z "${VIRTUAL_ENV}" ]]; then
if [[ -d ./venv && -f ./venv/bin/activate ]]; then
source ./venv/bin/activate
fi
elif [[ ! "$(pwd)" == ${VIRTUAL_ENV:0:n-5}* && ! -z "$(command -v deactivate)" ]]; then
deactivate
fi
}
Примечание: вам нужно добавить это в.bashrc
. Если не работает, проверьте, есть ли у вас.profile
не отменяет вашу команду (это случилось со мной)
На основе решения @MS_:
function cd() {
builtin cd "$@"
## If env folder is found then activate the vitualenv
if [[ -d ./venv ]] ; then
source ./venv/bin/activate
fi
if [[ -n "$VIRTUAL_ENV" ]] ; then
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate
parentdir="$(dirname "$VIRTUAL_ENV")"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
deactivate
fi
fi
}
pyenv-virtualenv
+
$ pyenv virtualenv 3.10.9 my-project
$ pyenv local my-project
Вот это.
Каждый раз, когда вы переходите в этот каталог проектаpyenv
автоматически:
- проверяет
.python-version
файл, созданныйpyenv local
- активирует виртуальную среду из
$HOME/.pyenv/versions/3.10.9/envs/my-project
Ссылка
Ответ с наибольшим количеством голосов мне не помог. Но добавив это в свой.bashrc
делал
# Automatically activate Python venv if it exists
auto_activate_venv() {
if [ -e ".venv/bin/activate" ]; then
source .venv/bin/activate
elif [ "$VIRTUAL_ENV" != "" ] && [ ! -e "$PWD/.venv" ]; then
deactivate
fi
}
# Override the 'cd' command to call our function
cd() {
builtin cd "$@" && auto_activate_venv
}
# If you use pushd/popd, you can override them too.
pushd() {
builtin pushd "$@" && auto_activate_venv
}
popd() {
builtin popd "$@" && auto_activate_venv
}
Вам не нужно выполнятьdeactivate
в каталоге, где существует venv. Когда виртуальная среда активна, вы можете деактивировать ее в любом месте.
Итак, скажем, у вас есть 2 venvs,<somepath>/project1/venv
и<somepath>/project2/venv
, и в настоящее времяproject1/venv
активен. Если вы хотите переключитьсяproject2/venv
, сделайте ниже.
cd project2
deactivate && source ./venv/bin/activate
Он деактивирует предыдущий и активирует текущий.
Теперь выше вы можете просто создать псевдоним или функцию оболочки в~/.zshrc
как показано ниже:
function avenv(){
deactivate
source ./venv/bin/activate
}
иди по пути где хочешь активировать venv и просто бегиavenv
.
Python venv имеет функцию под названием --prompt, при создании venv вы можете указать приглашение, чтобы в терминале вы понимали, какой venv активен.
python3 -m venv venv --prompt PROJECT1_VENV
Теперь в терминале это будет выглядеть как(PROJECT1_VENV) -> ~