我可以移动 virtualenv 吗?

Can I move a virtualenv?

这个问题不是重复的。

它不仅适用于 重命名 虚拟环境,而且实际上 移动 它到不同的目录,可能包括不同的用户目录。

这与仅仅重命名虚拟环境不同,尤其是对于不熟悉 virtualenvs 的人。

如果我创建一个 virtualenv,然后将它移到另一个文件夹,它还能工作吗?

$ virtualenv -p /usr/bin/python3 /home/me/Env/my-python-venv
$ source Env/my-python-venv/bin/activate
(my-python-venv) $ 

...那天晚些时候,虚拟环境移动了...

(my-python-venv) $ deactivate
$ mkdir -p /home/me/PeskyPartyPEnvs
$ mv /home/me/Env/my-python-venv /home/me/PeskyPartyPEnvs/

问题:

这行得通吗?

$ source /home/me/PeskyPartyPEnvs/my-python-venv/bin/activate
(my-python-venv) $ /home/me/PeskyPartyPEnvs/my-python-venv/bin/pip3 install foaas

我的意思是,这不是关于尝试这样做是否明智的问题(当然,除非这种智慧是幽默的),而是更多关于它是否可能的问题。我真的很想知道是否可以在 Python 3 中执行,或者我是否只需要 suck it up 并克隆它。

我能mv一个virtualenv那样不悲伤吗?我确实想避免悲伤。

是的,如果你没有做任何依赖于 virtualenv 当前目录的事情,这应该是可能的。

但是,如果您可以选择,最好的办法是创建新的 virtualenv 并开始使用新的 virtualenv。这是最安全的选择,以后出现问题的可能性最小。

文档 does mention that:

Each virtualenv has path information hard-coded into it,

例如,如果您有 运行 setvirtualenvproject 那么它将无法在您 运行 workon ... 之后切换到正确的目录,所以在这种情况下您需要手动修复它。

一般来说,virtualenv 只不过是一个包含必要的 Python 解释器文件和您需要的包的目录。

但是唉:

不,你不能简单地mv。有解决方法,但重新安装可能更容易。

(my-python-venv)$ /home/me/PeskyPartyPEnvs/pip3 install foaas
zsh: /home/me/PeskyPartyPEnvs/pip3: bad interpreter: /home/me/Env/my-python-venv/bin/python3: no such file or directory
(my-python-venv)$ deactivate
$ 

...沮丧地按enter很多,下面的工作

$
$
$ pip3 search foaas

除非它不是来自 my-python-venv,因此悲伤。

想要 mv 您的 virtualenv 并使用它,否则不修改?

简答:

嗯,你 不能

virtualenv--relocatable 参数似乎允许您这样做。

是的。可以在同一平台上移动它。您可以在现有环境中使用 --relocatable

来自 --help:

--relocatable -- Make an EXISTING virtualenv environment relocatable. This fixes up scripts and makes all .pth files relative.

然而,这似乎并没有改变 activate 脚本,而只是改变了 pip*easy_install* 脚本。在 activate 脚本中,$VIRTUAL_ENV 环境变量被硬编码为原始 /path/to/original/venv$VIRTUAL_ENV 变量也用于设置活动环境的 PATH,因此必须根据新位置更改它才能调用 pythonpip 等。没有绝对路径。

要解决此问题,您可以更改 activate 脚本中的 $VIRTUAL_ENV 环境变量(例如使用 sed),一切都会顺利进行。

用法示例:

$ cd ~/first
$ virtualenv my-venv
$ grep 'VIRTUAL_ENV=' my-venv/bin/activate
VIRTUAL_ENV="/home/username/first/my-venv"
$ virtualenv --relocatable my-venv
Making script my-venv/bin/easy_install relative
Making script my-venv/bin/easy_install-2.7 relative
Making script my-venv/bin/pip relative
Making script my-venv/bin/pip2 relative
Making script my-venv/bin/pip2.7 relative
### Note that `activate` has not been touched
$ mkdir ~/second
$ mv my-venv ~/second
$ cd ~/second
$ grep 'VIRTUAL_ENV=' my-venv/bin/activate
VIRTUAL_ENV=/home/username/first/my-venv
### (This variable hasn't been changed, it still refers to the old, now non-existent directory!)
$ sed -i -e 's|username/first|username/second|' my-venv/bin/activate
## sed can be used to change the path.
## Note that the `-i` (in place) flag won't work on all machines. 
$ source my-venv/bin/activate 
(my-venv) $ pip install foass
...
(my-venv) $ python 
[...]
> import foass

万岁,现在您可以安装东西并将它们加载到新定位的虚拟环境中。

使用这个和其他关于类似主题的线程的答案,我制作了一个 bash 脚本,在 virtualenv 目录本身 中找到并执行 ,这将有所帮助随着你的 virtualenv 移动。

完成 virtualenv --relocatable yourenv 后,每次移动目录时都需要更改 VIRTUAL_ENV 变量,因此如果您不想手动更改它,请使用它。

#!/bin/bash \n 
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
EXISTING=$(grep 'VIRTUAL_ENV=' bin/activate)  
NEWDIR=VIRTUAL_ENV=\"$DIR\"
sed -i -e "s|$EXISTING|$NEWDIR|" bin/activate
source bin/activate

希望对您有所帮助。

对于 Python 3.3+(带有新的 venv 内置模块)

简答(不分版本):

  • 没有干净、直接的方法来移动虚拟环境
  • 重新创建,很简单!!


长答案:

从 Python v3.3 开始,virtualenv 已成为名为 venv.

的内置模块

其他答案中提到的 --relocatable 选项未包含在 venv 中,目前我知道没有好的、安全的方法来重命名或重新定位 Python虚拟环境。

但是,使用所有当前安装的包重新创建虚拟环境相当简单。请参阅 ,或参阅以下部分。在此过程中,您可以在任意位置以任意名称重新创建新环境。

在上面链接的答案中,他提到了一些可能支持直接重命名或移动的第 3 方包。如果您决定寻求一种移动虚拟环境的方法,您可以研究一下这些方法是否也适用于 venv

注:在该回答中,重点是virtualenv,而不是venv。请参阅下一节了解如何翻译。



venv 对比旧的 virtualenv 命令语法

使用venv的命令是:

python -m venv

而不仅仅是 virtualenv,它作为命令安装在原始包中。其中“python”指的是您 运行 您的 python 可执行文件,它可以是各种各样的东西,例如:

  1. python
  2. pypy -3.7 或类似的(目前 Python 3.3+ 和 Windows 的 Python Launcher for Windows
  3. python3(双重安装 python 2 和 3 的 linux 环境的约定)
  4. 如果您遇到问题,请使用您想要 运行 的 python 可执行文件的绝对路径:例如c:\program files\python37\python.exe

如果您不确定 运行 是哪个版本,您可以随时 python --version 查找。



如何重新创建虚拟环境

Creating/recreating 虚拟环境很简单,使用一段时间后应该会成为第二天性。这个过程反映了你在前半部分将你的脚本作为一个包(及其依赖项)分发,然后有人会做什么来安装你的 script/package 以进行进一步开发。

首先,获取虚拟环境中内容的更新列表。激活它后,获取它使用的 Python 版本并将依赖项列表保存到文件中。

  1. 在激活虚拟环境的情况下使用 python --version 以查看它使用的 Python 版本。

    • 这是为了清楚起见 - 您可能出于各种原因想要更新 Python 版本 - 至少更新到最新的补丁版本
    • 例如,如果现有的 venv 使用的是 Python v3.7.4,但现在 v3.7.6 已过时 - 请改用 v3.7.6,它应该只包括非破坏性安全性和错误修复。
  2. 使用python -m pip freeze > requirements.txt创建当前包依赖列表,并将它们放入requirements.txt文件中。此命令肯定适用于 Linux 或 Git Bash - 不能 100% 确定 Windows.

    中的 Powershell 或命令行

现在创建一个新的虚拟环境,然后添加旧环境的依赖项。

  1. 创建新的 venv。

    • 确保您使用的 python 版本是您要安装到 venv 的正确版本。
    • 如果你希望它是完全相同的 Python 版本:
      • 运行 python 直接从当前虚拟环境(已激活),只需使用 python 作为命令
      • 或在虚拟环境文件夹
      • 中使用带有python.exe的绝对路径
    • 对于命令中的新 venv 文件夹条目:
      • 为所需的最终文件夹位置添加绝对路径或相对路径。
      • 使用 python -m venv my_new_venv 在当前工作目录的新 my_new_venv 文件夹中创建新的虚拟环境。
      • venv 文件夹的名称将是 venv 的名称(激活时提示中显示的名称)。
  2. requirements.txt 文件安装依赖项。

    • python -m pip install -r requirements.txt

您可能需要重新安装处于开发模式的本地包。

注意,如果您需要查看软件包安装到的具体位置,请使用:

  • python -m pip list -v
  • -v 或“verbose”选项将添加一些关于每个已安装包的额外​​信息,包括安装路径。这有助于确保您保持虚拟、用户和系统直接安装包。

此时你可以删除旧的venv文件夹和所有内容。我建议为此使用 GUI - 从 linux 命令行删除文件通常是永久性的,一个小的错字可能是个坏消息。

是的,你可以!(在 windows

解决方法很简单,只需将您的虚拟环境移动到任何地方,然后在 scripts\:

中编辑 activate.bat
  1. 将虚拟环境移至所需目录

  2. Right-click 并编辑位于 venv_folder\scripts.

    activate.bat
  3. 更改 VIRTUAL_ENV 变量自:

     set VIRTUAL_ENV=C:\old_directory\venv_name
    

    进入

     set VIRTUAL_ENV=C:\new_directory\venv_name
    
  4. 保存编辑好的批处理文件,就这样!

注意:我的解决方案应该有效并保存 windows users 设置新的虚拟环境,我怀疑这是否适用于其他操作系统,因为 .bat 来自 MS-DOS

TL;DR

virtualenv-clone is included part of virtualenvwrapper

virtualenv-clone /path/to/old/venv /path/to/new/venv

或者

你也可以试试cpvirtualenv

cpvirtualenv /path/to/old/venv /path/to/new/venv

但是 cpvirtualenv 期望 /path/to/old/venv 存在于 $WORKON_HOME 中,如果不存在则失败。由于这会调用 virtualenv-clone,您不妨使用它;避免像

这样的错误
mark@Desktop:~/venvs$ cpvirtualenv ./random/ $WORKON_HOME/random
Copying random as /home/mark/.virtualenvs/venvs/random...
Usage: virtualenv-clone [options] /path/to/existing/venv /path/to/cloned/venv

virtualenv-clone: error: src dir '/home/mark/.virtualenvs/venvs/random' does not exist

根据 virtualenvwrapper documentation

的警告

Copying virtual environments is not well supported. Each virtualenv has path information hard-coded into it, and there may be cases where the copy code does not know it needs to update a particular file. Use with caution.

它实际上有什么作用? 根据 virtualenv-clone PyPi page

A script for cloning a non-relocatable virtualenv.

Virtualenv provides a way to make virtualenv's relocatable which could then be copied as we wanted. However making a virtualenv relocatable this way breaks the no-site-packages isolation of the virtualenv as well as other aspects that come with relative paths and /usr/bin/env shebangs that may be undesirable.

Also, the .pth and .egg-link rewriting doesn't seem to work as intended. This attempts to overcome these issues and provide a way to easily clone an existing virtualenv.

It performs the following:

copies sys.argv[1] dir to sys.argv[2]

updates the hardcoded VIRTUAL_ENV variable in the activate script to the new repo location. (--relocatable doesn't touch this)

updates the shebangs of the various scripts in bin to the new Python if they pointed to the old Python. (version numbering is retained.)

it can also change /usr/bin/env python shebangs to be absolute too, though this functionality is not exposed at present.

checks sys.path of the cloned virtualenv and if any of the paths are from the old environment it finds any .pth or .egg link files within sys.path located in the new environment and makes sure any absolute paths to the old environment are updated to the new environment.

finally it double checks sys.path again and will fail if there are still paths from the old environment present.

NOTE: This script requires Python 2.7 or 3.4+

我写了一个venv-move脚本。

第一个参数是 venv 的路径。它会删除该路径下的任何 __pycache__

检测到旧路径,确认后替换为当前路径。它似乎工作正常,即使在移动到同一类型的不同机器时也是如此。

在Python中重写这个是有意义的,但程序会更长。

#!/bin/bash -eu
venv=
old=`perl -ne '/VIRTUAL_ENV="(.*?)"/ && print "\n"' "$venv/bin/activate"`
new=$PWD/$venv
find "$venv" -name __pycache__ | xargs rm -rf --
files=`fgrep -r "$old" "$venv" -l`
echo "replace $old with $new in:"
echo "$files"
read -p "[yn] ? " YN
[ "$YN" = y ]
sed -i "s:$old:$new:g" $files