Как автоматически активировать virtualenvs, когда cd'ing в каталог
У меня есть куча проектов в моих ~/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
плагин oh-my-zsh
который делает это. (Что я мог бы сделать, если ответы здесь тусклые.
Ответы
Ответ 1
Поместите что-то подобное в ваш.zshrc
function cd() {
if [[ -d ./venv ]] ; then
deactivate
fi
builtin cd $1
if [[ -d ./venv ]] ; then
. ./venv/bin/activate
fi
}
Изменить: как отмечено в комментариях, cd
-ing в подпапку текущего виртуального env дезактивирует его. Одной из идей может быть деактивация текущего env, только если cd
-ing в новый, например
function cd() {
builtin cd $1
if [[ -n "$VIRTUAL_ENV" && -d ./venv ]] ; then
deactivate
. ./venv/bin/activate
fi
}
который все еще может быть улучшен, возможно, превратив его в "подсказку" или попытку сопоставления префикса в именах папок, чтобы проверить там виртуальный env где-то по пути, но мой shell-fu недостаточно хорош.
Ответ 2
Добавьте следующее в ваш .bashrc или .zshrc
function cd() {
builtin cd "[email protected]"
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.
Ответ 3
Вместо написания собственного скрипта вы можете использовать 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
Ответ 4
Это мое решение, которое:
- проверяет, есть ли уже на текущем активном
venv
, и ничего не делает в этом случае - если есть папка
venv
, деактивируйте активную, если она есть - активировать новый
venv
независимо от того, был ли старый или нет.
В моем bash_aliases
:
function cd() {
builtin cd "[email protected]"
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
}
Ответ 5
Для потомков: я использовал решение @MS_, но столкнулся с проблемой, при которой cd
непосредственно из одного проекта в другой деактивирует старый virtualenv, но не активирует новый. Это слегка измененная версия этого решения, которое решает эту проблему:
# auto activate virtualenv
# Modified solution based on https://stackoverflow.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function cd() {
builtin cd "[email protected]"
## 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
}
Ответ 6
это решение без cd'ing, с zsh, установленным в setop auto_cd
, мы сможем изменять каталоги без cd, просто введите имя каталога и нажмите Enter.
это преимущество вышеуказанного решения:
# auto activate virtualenv
# Modified solution based on https://stackoverflow.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")
Ответ 7
Вот (еще) другое решение для автоматической активации виртуальной среды; это основано на ряде ответов, уже размещенных здесь.
Это будет работать для любого имени или каталога виртуальной среды (не только для ./env
, ./venv
и т.д.). Также поддерживает подкаталоги, а также cd
-ing в символические ссылки папок виртуальной среды (родительских).
Этот код ищет файл pyvenv.cfg
вместо определенного именованного каталога. Если он найден в подкаталоге текущей папки, среда автоматически активируется. Находясь в виртуальной среде, это состояние сохраняется до тех пор, пока вы не выйдете из каталога родительской виртуальной среды, после чего среда будет деактивирована.
Поместите это в свой .bashrc
или .bash_profile
.
function cd() {
builtin cd "[email protected]"
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
}
Лично я считаю, что это улучшение для многих решений, поскольку оно должно работать в любой виртуальной среде.