有没有可能污染环境?
问题描述
我在PyCharm中设置了一个项目,并且有一个现有的CONDA环境。我的脚本在控制台内运行时有效。
我希望能够从任何位置运行python -m path_to_my_script/script.py
,但我需要激活Conda。Conda建议我这样做conda init
,但我担心它可能会在某个地方更改设置并损坏某些东西。
conda init
做什么?
解决方案
应答策略
conda init
命令的确切功能及其结果是特定于shell的。与其试图涵盖所有案例,不如让我们浏览一个案例,并注意到人们可以通过替换感兴趣的外壳来复制这种分析。
案例研究:conda init zsh
让我们看一下zsh
作为shell。这是一个通用的shell(MacOS10.15+的默认shell),非常接近bash。另外,我还没有配置它。
探测命令:演练
许多CONDA命令都通过--dry-run, -d
标志包含某种形式的模拟运行功能,该标志与详细标志相结合,可以在不执行它们的情况下查看它会做什么。对于init
命令,仅预演只会告诉我们将修改哪些文件:
$ conda init -d zsh
no change /Users/mfansler/miniconda3/condabin/conda
no change /Users/mfansler/miniconda3/bin/conda
no change /Users/mfansler/miniconda3/bin/conda-env
no change /Users/mfansler/miniconda3/bin/activate
no change /Users/mfansler/miniconda3/bin/deactivate
no change /Users/mfansler/miniconda3/etc/profile.d/conda.sh
no change /Users/mfansler/miniconda3/etc/fish/conf.d/conda.fish
no change /Users/mfansler/miniconda3/shell/condabin/Conda.psm1
no change /Users/mfansler/miniconda3/shell/condabin/conda-hook.ps1
no change /Users/mfansler/miniconda3/lib/python3.7/site-packages/xontrib/conda.xsh
no change /Users/mfansler/miniconda3/etc/profile.d/conda.csh
modified /Users/mfansler/.zshrc
==> For changes to take effect, close and re-open your current shell. <==
在这里,我们可以看到它计划将zsh的用户级资源文件作为目标,/Users/mfansler/.zshrc
,但是它没有告诉我们它将如何修改它。还有,天哪!这里的UX很糟糕,因为它根本不能反映我使用-d
标志的事实。但是不要担心:只要-d
标志还在,它实际上不会改变事情。
修补程序预览
要查看它到底将执行什么操作,请向命令添加单个详细标志(-v
)。这将提供以前输出中的所有内容,但现在将向我们显示它将用于修补(更新).zshrc
文件的差异。
$ conda init -dv zsh
/Users/mfansler/.zshrc
---
+++
@@ -0,0 +1,16 @@
+
+# >>> conda initialize >>>
+# !! Contents within this block are managed by 'conda init' !!
+__conda_setup="$('/Users/mfansler/miniconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
+if [ $? -eq 0 ]; then
+ eval "$__conda_setup"
+else
+ if [ -f "/Users/mfansler/miniconda3/etc/profile.d/conda.sh" ]; then
+ . "/Users/mfansler/miniconda3/etc/profile.d/conda.sh"
+ else
+ export PATH="/Users/mfansler/miniconda3/bin:$PATH"
+ fi
+fi
+unset __conda_setup
+# <<< conda initialize <<<
+
# ...the rest is exactly as above
也就是说,行动计划是将这16行添加到.zshrc
文件中。在本例中,我没有现有的.zshrc
文件,因此它计划将其添加到第1行。如果该文件已经存在,它将追加这些行。
解释外壳代码
在关注细节之前,让我们先概述一下这段代码。从本质上讲,这是设置某些shell功能的冗余尝试序列。它们从功能最强到功能最差排序。
孔达希望做什么
代码
__conda_setup="$('/Users/mfansler/miniconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
从conda
本身获取一些内容,将结果存储到一个字符串中,然后如果命令有干净的退出($? -eq 0
),则计算该字符串。这里的巧妙工程是子进程(技术上python -m conda
)传回可以在当前进程(zsh
)中运行的结果,从而允许它定义shell函数。
稍后我将通过挖洞更深入地了解这里发生的事情。
后备1:硬编码外壳函数
如果这个奇怪的内部命令失败,DEVS会包含一些基本shell函数的硬编码版本(特别是conda activate
)。这位于:
miniconda3/etc/profile.d/conda.sh
他们只需检查文件是否存在并将其作为源文件即可。让我们点击最后一个选项,然后返回查看功能。
后备2:最后的避难所
绝对最后的办法是从字面上违反Conda v4.4以来的标准建议,即简单地将基本环境的bin
目录放在PATH
上。在这种情况下,没有conda activate
功能;这只会确保Conda在您的路径上。
详细信息:shell功能
回到预期的情况,我们可以通过简单地获取字符串结果来准确检查它将计算什么:
$ conda shell.zsh hook
__add_sys_prefix_to_path() {
# In dev-mode CONDA_EXE is python.exe and on Windows
# it is in a different relative location to condabin.
if [ -n "${_CE_CONDA}" ] && [ -n "${WINDIR+x}" ]; then
SYSP=$(dirname "${CONDA_EXE}")
else
SYSP=$(dirname "${CONDA_EXE}")
SYSP=$(dirname "${SYSP}")
fi
if [ -n "${WINDIR+x}" ]; then
PATH="${SYSP}/bin:${PATH}"
PATH="${SYSP}/Scripts:${PATH}"
PATH="${SYSP}/Library/bin:${PATH}"
PATH="${SYSP}/Library/usr/bin:${PATH}"
PATH="${SYSP}/Library/mingw-w64/bin:${PATH}"
PATH="${SYSP}:${PATH}"
else
PATH="${SYSP}/bin:${PATH}"
fi
export PATH
}
__conda_exe() (
__add_sys_prefix_to_path
"$CONDA_EXE" $_CE_M $_CE_CONDA "$@"
)
__conda_hashr() {
if [ -n "${ZSH_VERSION:+x}" ]; then
ehash
elif [ -n "${POSH_VERSION:+x}" ]; then
: # pass
else
hash -r
fi
}
__conda_activate() {
if [ -n "${CONDA_PS1_BACKUP:+x}" ]; then
# Handle transition from shell activated with conda <= 4.3 to a subsequent activation
# after conda updated to >= 4.4. See issue #6173.
PS1="$CONDA_PS1_BACKUP"
unset CONDA_PS1_BACKUP
fi
local ask_conda
ask_conda="$(PS1="${PS1:-}" __conda_exe shell.posix "$@")" || eturn
eval "$ask_conda"
__conda_hashr
}
__conda_reactivate() {
local ask_conda
ask_conda="$(PS1="${PS1:-}" __conda_exe shell.posix reactivate)" || eturn
eval "$ask_conda"
__conda_hashr
}
conda() {
local cmd="${1-__missing__}"
case "$cmd" in
activate|deactivate)
__conda_activate "$@"
;;
install|update|upgrade|remove|uninstall)
__conda_exe "$@" || eturn
__conda_reactivate
;;
*)
__conda_exe "$@"
;;
esac
}
if [ -z "${CONDA_SHLVL+x}" ]; then
export CONDA_SHLVL=0
# In dev-mode CONDA_EXE is python.exe and on Windows
# it is in a different relative location to condabin.
if [ -n "${_CE_CONDA:+x}" ] && [ -n "${WINDIR+x}" ]; then
PATH="$(dirname "$CONDA_EXE")/condabin${PATH:+":${PATH}"}"
else
PATH="$(dirname "$(dirname "$CONDA_EXE")")/condabin${PATH:+":${PATH}"}"
fi
export PATH
# We're not allowing PS1 to be unbound. It must at least be set.
# However, we're not exporting it, which can cause problems when starting a second shell
# via a first shell (i.e. starting zsh from bash).
if [ -z "${PS1+x}" ]; then
PS1=
fi
fi
conda activate base
我不打算详细介绍所有这些内容,但主要部分不是直接将bin
放在path上,而是定义一个名为conda
的shell函数,该函数用作condabin/conda
入口点的包装器。这还定义了一个新功能conda activate
,它在幕后使用shell函数__conda_activate()
。在最后一步,它然后激活基础环境。为什么要这样做?
这是这样设计的,以便响应配置设置。配置选项(如auto_activate_base
和change_ps1
)会影响Conda处理shell的方式,因此会更改Conda在其shell函数中包含的功能。
Conda";是否污染环境?
不完全是。可以通过配置设置禁用自动激活和提示修改等主要行为功能,因此conda init
最终只需将conda activate
功能添加到shell中,无需手动操作路径即可在环境之间进行干净切换。
相关文章