virtualenv和virtualenvwrapper实现了Python第三方库的有效管理 , 但是仍然存在一些可以改进的地方。比如 : requirements.txt 的功能较弱 , 在requirements.txt中仅仅列出了虚拟环境中安装的所有第三方库的名称和版本号 , 没有反应出第三库之间的依赖关系。再比如 : requirements.txt需要手动生成和更新。要手动的执行 pip3 freeze > requirements.txt 才能得到requirements.txt。如果安装或卸载了第三方库 , 需要再次执行指令以得到更新的requirements.txt。再比如 : pip和virtualenv是两个独立的工具 , 能合成一个工具是不是更好呢? 第三方库 Pipenv: Python Development Workflow for Humans 就是综上所述的改进工具 , pip + virtualenv的结合体 , 也是Python官方推荐的第三方库管理工具。
pipenv 是一款比较新的包管理工具 , 其借鉴了 javascript 的 npm 和 PHP 的 composer 等理念 , 通过一个依赖描述文件 Pipfile 来安装和管理依赖 , 以达到协同开发的目的。如果你熟悉 npm 或者 composer 的话 , 那 pipenv 正合你胃口。pipenv 其实整合了 pip 和 virtualenv 等库 , 在其上推出了更便捷的使用方式。
1. 安装pipenv
直接使用pip命令安装
pip3 install pipenv设置命令行的自动补全功能
如果使用的bash shell , 请将以下代码添加到.bashrc或.bash_profile文件内:
eval "$(pipenv --completion)"命令详解 :
$ pipenv
Usage: pipenv [OPTIONS] COMMAND [ARGS]...
Options:
--where 输出项目根目录相关信息
--venv 输出virtualenv相关信息
--py 输出Python解释器相关信息
--envs 输出环境变量选项
--rm 删除virtualenv
--bare 最小化输出
--completion 命令自动补全
--man 显示man页面
--three / --two 在创建virtualenv时使用Python3或Python2
--python TEXT 指定创建virtualenv时使用的具体的Python版本
--site-packages 为virtualenv启用site-packages [env变量 : PIPENV_SITE_PACKAGES]
--clear 清除缓存(pipenv , pip和pip-tools ) [env变量 : PIPENV_CLEAR]
--pypi-mirror TEXT 指定一个PyPI镜像
--version 显示版本信息并退出
-h, --help 显示帮助信息并退出
使用示例:
创建一个项目 , 并明确指定使用Python3.7:
$ pipenv --python 3.7
删除项目的virtualenv (inferred from current directory):
$ pipenv --rm
为项目安装所有依赖项 (including dev):
$ pipenv install --dev
创建包含pre-releases的lockfile文件:
$ pipenv lock --pre
将已安装的依赖项显示为图表:
$ pipenv graph
检查已安装的依赖项是否存在安全漏洞:
$ pipenv check
安装一个本地的setup.py到你的虚拟环境或Pipfile:
$ pipenv install -e .
使用原生的pip命令:
$ pipenv run pip freeze
Commands:
check 根据 Pipfile 中提供的PEP 508标记检查安全漏洞
clean 卸载所有 Pipfile.lock 未指定的包
graph 显示当前安装的依赖项的关系图信息
install 如果未指定要安装的包 , 则会安装 Pipfile 中的所有包 , 否则 , 只安装指定的包
lock 生成 Pipfile.lock 文件
open 在编辑器中查看给定的模块
run 运行virtualenv中已安装的命令
shell 在virtualenv内启动一个shell
sync 安装 Pipfile.lock 中指定的所有的包
uninstall 卸载一个指定的包并将其从 Pipfile 中移除
update 先运行lock命令 , 在运行sync命令2. pipenv虚拟环境管理
2.1 虚拟环境创建与激活
创建虚拟环境
[root@host-192-168-71-25 ~]# mkdir /data/projenv8 [root@host-192-168-71-25 ~]# cd /data/projenv8 [root@host-192-168-71-25 projenv8]# ls [root@host-192-168-71-25 projenv8]# pipenv install Creating a virtualenv for this project Pipfile: /data/projenv8/Pipfile Using /usr/bin/python3.12.9 to create virtualenv... ⠴ Creating virtual environment...created virtual environment CPython3.12.9.final.0-64 in 258ms creator CPython3Posix(dest=/root/.virtualenvs/projenv8-73W4Qy2h, clear=False, no_vcs_ignore=False, global=False) seeder FromAppData(download=False, pip=bundle, via=copy, app_data_dir=/root/.local/share/virtualenv) added seed packages: pip==25.1.1 activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator ✔ Successfully created virtual environment! Virtualenv location: /root/.virtualenvs/projenv8-73W4Qy2h Creating a Pipfile for this project... Pipfile.lock not found, creating... Locking dependencies... Locking dependencies... Updated Pipfile.lock (702ad05de9bc9de99a4807c8dde1686f31e0041d7b5f6f6b74861195a52110f5)! To activate this project's virtualenv, run pipenv shell. Alternatively, run a command inside the virtualenv with pipenv run. Installing dependencies from Pipfile.lock (2110f5)...上面的命令会自动在
~/.virtualenvs/目录下创建虚拟环境目录 , 名字为一个当前目录名加一串随机字符串的虚拟环境目录。这里是projenv8-73W4Qy2h下面多了两个文件 , 为
Pipfile和Pipfile.lock, 用于存放依赖包名的文件。类似php里的composer.json和composer.lock。[root@host-192-168-71-25 projenv8]# ls Pipfile Pipfile.lock查看虚拟环境
[root@host-192-168-71-25 projenv8]# pipenv --venv /root/.virtualenvs/projenv8-73W4Qy2h我们的虚拟环境目录在
/root/.virtualenvs/下面 , 是因为我们之前设置过环境变量export WORKON_HOME=$HOME/.virtualenvs激活虚拟环境 , 直接切换到对应目录
/data/projenv8并运行命令pipenv shell即可[root@host-192-168-71-25 projenv8]# cd /data/projenv8/ [root@host-192-168-71-25 projenv8]# pipenv shell Launching subshell in virtual environment... source /root/.virtualenvs/projenv8-73W4Qy2h/bin/activate [root@host-192-168-71-25 projenv8]# source /root/.virtualenvs/projenv8-73W4Qy2h/bin/activate (projenv8) [root@host-192-168-71-25 projenv8]#激活过程中如果出现下面类似告警:
Warning: Your Pipfile requires python_version 2.7, but you are using 3.9.9 (/root/./m/bin/python).原因 : 这是因为创建虚拟环境的时候 , 没有指定
python解释器 ,Pipfile就使用系统默认的python解释器了 , 就是2.7.5, 但是pipenv却是使用系统最新的解释器3.9解决办法:
办法一 : 手动修改
Pipfile手动修改
Pipfile文件里的python_version注意 :
Pipfile.lock里的也要修改vim Pipfile [[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [packages] [dev-packages] [requires] python_version = "3.9"办法二 : 删除虚拟环境 , 重新创建虚拟环境
删除虚拟环境后 , 再次安装会覆盖之前的
Pipfile, 使用新环境。如果不删除 , 无法覆盖。# pipenv --rm删除当前虚拟环境 , 注意Pipfile不会被删掉 [root@ops-130 myproj10]# pipenv --rm # 使用pipenv重新安装 , 指定解释器版本为3.X [root@ops-130 myproj10]# pipenv install --three # 此时再次查看Pipfile版本就和环境一致了。 [root@ops-130 myproj10]# cat Pipfile
退出虚拟环境 : exit
(projenv8) [root@host-192-168-71-25 projenv8]# exit exit [root@host-192-168-71-25 projenv8]#删除虚拟环境
[root@host-192-168-71-25 projenv8]# pipenv --rm Removing virtualenv (/root/.virtualenvs/projenv8-73W4Qy2h)...
2.2 创建虚拟环境的多种方式
pipenv创建虚拟环境有多种方式 , 这里总结一下 :
方式一: 指定解释器创建虚拟环境
# 创建虚拟环境 , 指定使用python3 pipenv --three # 或者 pipenv --python 3.9这种方式是指定
python解释器 , 并创建虚拟环境。它会在当前目录生成
Pipfile, 不会生成Pipfile.lock方式二: 安装所有依赖时创建虚拟环境
# 创建虚拟环境 pipenv install这种方式是在安装依赖包的同时创建虚拟环境。
因为
pipenv install, 就是根据Pipfile来安装所有依赖 , 类似npm install如果当前目录没有
Pipfile, 它就会自动创建Pipfile并创建虚拟环境。因为这种方式它已经在安装所有依赖了 , 所以不仅会创建
Pipfile, 也会创建Pipfile.lock文件。同时 , 它创建虚拟环境后 , 也会自动进入环境 , 但是也不会显示前缀。
方式三 : 激活时创建虚拟环境
# 激活 , 如果环境不存在 , 则创建虚拟环境并激活 pipenv shell这个命令主要用于激活环境 , 但是如果环境不存在 , 则会先创建虚拟环境 , 并同时激活虚拟环境。
这种方式因为使用了
pipenv shell激活了 , 所以创建虚拟环境后 , 也会自动进入虚拟环境 , 并激活。会显示虚拟环境前缀。
2.3 创建虚拟环境目录位置
方式一:
# 设置这个环境变量 , pipenv会在当前目录下创建.venv的目录 , 以后都会把模块装到这个.venv下。 export PIPENV_VENV_IN_PROJECT=1方式二:
# 自己在项目目录下手动创建.venv的目录 , 然后运行 pipenv run 或者 pipenv shell pipenv都会在.venv下创建虚拟环境。 mkdir .venv pipenv shell方式三 :
# 设置WORKON_HOME到其他的地方 ( 如果当前目录下已经有.venv,此项设置失效 ) 。 export WORKON_HOME=$HOME/.virtualenvs
小技巧: 如果子级目录的父级目录已经创建过虚拟环境, 则子级目录无法创建虚拟目录(子级目录无法生成Pipfile, 子级默认会使用父级的虚拟环境), 如果确实需要在子级目录创建独立的虚拟环境,可以运行pipenv --where 获取父级虚拟环境的名字, 根据虚拟环境的前半部分名字, 确定父级目录的位置, 然后删除父级目录下的Pipfile, Pipfile.lock, 运行exit退出父级虚拟环境,然后回到子目录,运行pipenv --three创建子目录的虚拟环境即可
2.4 相关定位操作
定位项目目录
[root@host-192-168-71-25 projenv8]# pipenv --where /data/projenv8定位虚拟环境目录, 即
virtualenv目录[root@host-192-168-71-25 projenv8]# pipenv --venv /root/.virtualenvs/projenv8-73W4Qy2h定位
Python解释器:[root@host-192-168-71-25 projenv8]# pipenv --py /root/.virtualenvs/projenv8-73W4Qy2h/bin/python
3. pipenv包管理
安装依赖包 :
安装相关依赖包, 并加入到
Pipfilepipenv install flask它会在当前环境安装
flask依赖包 , 并记录flask包名以及版本信息 , 记录到Pipfile里。如果安装的时候 , 没有指定包名 , 默认是最新的 , 会记录为“
*”注意 :
Pipfile只会记录你install里指定的包 , 但是这个flask包本身所依赖的包不会记录 ,但是所有的依赖详情都会记录到
Pipfile.lock中。
查看目前安装的库及其依赖关系
pipenv graph这里所有的完整依赖关系, 这些会记录到
Pipfile.lock中(projenv8) [root@host-192-168-71-25 projenv8]# pipenv graph Flask==3.1.1 ├── blinker ├── click ├── itsdangerous ├── Jinja2 │ └── MarkupSafe ├── MarkupSafe └── Werkzeug └── MarkupSafe Pipfile会记录当前虚拟环境安装的所有依赖包及其对应的版本 , 当我们需要迁移项目 , 部署新项目 , 或者有新人接手时 , 就可以直接拿到这个Pipfile和Pipfile.lock文件 , 直接pipenv install即可 , 它就会按照Pipfile里的包 , 把所有的依赖文件都安装上 , 是不是很方便。安装所有依赖包:
# 根据Pipfile的记录 , 安装所有依赖包 pipenv install指定安装包版本
你可以使用 语义化(https://semver.org/)的版本控制方案 指定包的版本。例如
major.minor.micro。例如 , 你可以使用如下的命令安装
requests:pipenv install requests~=1.2 # 相当于 requests~=1.2.0Pipenv将安装1.2版本和任何minor版本的更新 , 但不会安装2.0版本。上面的命令将会自动更新
Pipfile文件以体现这个特殊的需求。通常 ,
Pipenv使用与pip相同的参数格式。但是 , 请注意 , 根据PEP 440, 您不能使用包含连字符或加号的版本号。要指定包含或者排除具体的版本 , 您可以使用如下命令 :
pipenv install "requests>=1.4" # 只安装等于或者大于 1.4.0 的版本 pipenv install "requests<=2.13" # 只安装小于或者等于 2.13.0 的版本 pipenv install "requests>2.19" # 安装 2.19.1 版本但是不安装 2.19.0 版本注意 : 强烈建议使用双引号包裹包名和版本号以避免
unix操作系统中的输入和输出重定向问题。请优先使用
~=标识符而不是==标识符 , 因为后者会阻止pipenv更新包 :pipenv install "requests~=2.2" # 锁定包的主版本(这相当于使用==2.*)要避免安装某个特定的版本 , 可以使用
!=标识符。要深入解释有效标识符和更复杂的用例 , 请查看
PEP-440的相关部分。https://www.python.org/dev/peps/pep-0440/#version-specifiers%3E
卸载依赖包
卸载指定包:
pipenv uninstall flask卸载包后 , 相关包和依赖详情会从
Pipfile和Pipfile.lock中移除。
卸载当前环境所有包:
# 从虚拟环境中移除所有已安装的包 , 但 Pipfile.lock 文件不受影响 pipenv uninstall --all卸载开发包:
# 从虚拟环境中卸载所有开发包 , 并从 Pipfile 文件中移除这些包 pipenv uninstall –all-dev更新依赖包 :
查看所有需要更新的包:
pipenv update --outdated如下图:

更新指定包:
pipenv update <包名>更新所有包:
pipenv update检查安全漏洞:
pipenv check # 检查安全漏洞它可能会检查出很多错误 , 其实如果不影响你使用 , 你可以直接忽略掉。强迫症患者也可以一个一个问题去解决。
比如如下问题:

修改
pipenv的镜像源可以修改当前目录下
Pipfile文件 , 将[source]下的url属性改成国内的源即可:[[source]] url = "https://mirrors.aliyun.com/pypi/simple" verify_ssl = true name = "pypi"
4. 环境部署
使用pipenv进行多环境部署
dev与正式环境区分安装。
当你想要一个包只在开发环境使用 , 等生产部署的时候 , 不需要该安装包 , 你可以这样指定环境安装。
# 把django安装在开发环境
pipenv install django --dev安装如下图

安装完成后 , 查看Pipfile文件 :
会发现 , pipenv已经将安装包区分开来了。
[dev-packages] 里记录的--dev开发环境安装的包
[package] 里记录的是没有加环境参数 , 默认就是正式环境的包。

那么等到你真正迁移到生产环境部署的时候 , 就只需要这么做 :
pipenv install 这样默认是只安装[package] 里的安装包的 , 会自动过滤掉[dev-packages] 里的包。
让生产环境变得更加纯净 , 避免有多余的包。
如下 : 这是直接pipenv install的 , 里面是没有django包的

如果你要迁移到开发环境 , 只需要这么做 :
pipenv install --dev它就会把[dev-packages] 里的包也一起安装上了。
如下 :
这是使用了--dev参数的 , 看到已经把djiango安装上了。

5. Pipfile.lock文件
Pipfile.lock 利用了pip中一些新的安全改进。默认情况下 , Pipfile.lock 包含每个下载的包的 sha256 哈希值。这可以使pip能够保证从不信任的PyPI源安装包时或者在不稳定的网络环境下安装包时都能保证包的正确性与完整性。我们强烈建议通过将项目从开发环境提升到生产环境来进行部署。您可以使用 pipenv lock 编译开发环境上的依赖项 , 并将编译后的 Pipfile.lock 文件部署到您所有的生产环境 , 以便进行可重现的构建。
(使用Pipfile.lock可以锁定之前的安装包 , 确保迁移重新部署后 , 能够重现跟之前一样的环境。)
Pipfile和Pipfile.lock不一致
因为使用pipenv install的时候 , 加上--ignore-lock参数 , 可以忽略 Pipfile.lock 文件而直接安装 Pipfile 中的包。此外 , 不会更新 Pipfile.lock 文件。
当pipenv install安装一些比较大的包 , 比如TensorFlow等科学包 , 在安装完包 , 正在解析包依赖的时候 , 可能会花费很长时间 , 可能就会ctrl+C停止掉了 , 此时包已经安装完成 , Pipfile已经写入完成 , 但是没有解析完依赖 , 所以Pipfile.lock没有写入完成。
这两种情况都会导致Pipfile和Pipfile.lock不一致的情况 , 会对应不上。
此时 , 可以使用Pipenv lock重新生成Pipfile.lock文件。
pipenv lock
如果通过 pipenv 命令安装和卸载 package , 安装或卸载完成后还会更新 Pipfile.lock 文件 , 有时候会卡在这个步骤。通常可以 ctrl+c 强制推出 , 删除 Pipfile.lock, 然后 使用命令重新生成Pipfile.lock文件
# 重新生成Pipfile.lock文件
pipenv lock默认情况下 , 使用pipenv install , 它会重新解析Pipfile里安装包的依赖性 , 并将依赖关系更新到Pipfile.lock中。如果你不想要重新解析Pipfile里安装包 , 只想安装Pipfile.lock文件中现存的依赖包 , 可以精确的指定只使用Pipfile.lock文件。
pipenv sync
可以使用 sync 命令精确安装 Pipfile.lock 文件中指定的包 :
pipenv sync注意 : pipenv install --ignore-pipfile 和 pipenv sync 命令很相似 , 但是pipenv sync 命令永远不会尝试重新锁定依赖项 , 因为它被认为是一个原子操作。默认情况下 , 除非使用了 --deploy 标志 , 否则 pipenv install 会尝试重新锁定依赖项。
pipenv install --deploy可以使用 --deploy 标志强制Pipfile.lock 文件是最新的。
上述命令将在Pipfile.lock 文件不是最新的时候导致构建失败 , 而不是生成一个新的。
6. 兼容requirements.txt
之前我们的pip工具可以从requierments.txt文件中导入依赖包。
在
pipenv, 用下面的命令就可以将Pipfile和Pipfile.lock文件里面的包导出为requirements.txt文件。# 将Pipfile里的全部包导出到requirements.txt pipenv lock -r > requirements.txt
选择只导出开发环境的包:
# 只导出开发环境的包 pipenv lock -r --dev-only > requirements.txt
导出开发环境+ 默认环境的包:
# dev环境和default环境的包都会导出 pipenv lock -r --dev > requirements.txt
使用底层pip的命令导出:
pipenv run pip freeze > requirements.txt
导入
requirements.txt导出为
requirements.txt后 , 可以通过pip导入 , 也可以通过pipenv导入。# 通过pip导入 pip install -r requirements.txt # 通过pipenv导入 pipenv install -r requirements.txt
7. 虚拟环境中运行命令
启动
shell运行正常来说 , 如果想要让命令运行在虚拟环境 , 需要启动一个虚拟环境的
shell, 否则命令还是在系统环境下运行的 , 如下 :pipenv shell
使用
run运行如果不想启动
shell, 而是直接在虚拟环境中执行命令 , 可以使用run:# pipenv run <命令> pipenv run python --version
部署项目的时候 , 你也可以不进入虚拟环境的方式运行项目 :
pipenv run python xxx.py
8. 环境变量: (.env)
自动加载
.env文件(利器).env文件可以设置一些环境变量 , 在程序开发的时候模拟环境变量。如果项目目录下包含一个
.env文件 , 它会被pipenv shell和pipenv run命令自动加载 :# 如下 , 设置一个变量HELLO , 以及配置文件路径的变量 [root@ops-130 myproj10]# cat .env HELLO=WORLD CONFIG_PATH=${HOME}/.config/foo # 测试环境变量 # 使用pipenv run的时候 , 会自动加载该环境变量。 [root@ops-130 myproj10]# pipenv run python Loading .env environment variables... Python 3.9.9 (main, Dec 31 2021, 15:34:46) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os.environ['HELLO'] 'WORLD' >>> os.environ['CONFIG_PATH'] '/root/.config/foo' >>>这类似于
php的lavel框架的.env文件。这对于将生产凭证排除在代码库之外非常有用。我们不建议将 .env 文件提交到源代码控制中!
如果你的
.env文件位于不同的路径下或者有其他名称 , 你可以设置一个PIPENV_DOTENV_LOCATION环境变量:PIPENV_DOTENV_LOCATION=/path/to/.env pipenv shell要禁止
pipenv加载.env文件 , 可以设置PIPENV_DONT_LOAD_ENV环境变量:PIPENV_DONT_LOAD_ENV=1 pipenv shellPipfile引用环境变量在
Pipfile中也可以引用环境变量的值 , 格式为${MY_ENVAR}或$MY_ENVAR, 在Windows系统中还支持%MY_ENVAR%。[[source]] url = "https://${PYPI_USERNAME}:${PYPI_PASSWORD}@my_private_repo.example.com/simple" verify_ssl = true name = "pypi" [packages] flask = "*" jieba = "*" [dev-packages] django = "*" [requires] python_version = "3.9"这里的变量为:
${PYPI_USERNAME}:${PYPI_PASSWORD}使用前提是 , 系统中要已经设置了相关的变量。
当然你可以结合
.env文件 , 将相关变量设置在.env里。
从
setup.py安装依赖包很多依赖库都包含
setup.py文件 , 里面也包含了对应包的子依赖信息 , 这个文件跟Pipfile.lock有点相似 ,pipenv也提供了堆setup.py的支持。pipenv也可以从setup.py安装:pipenv install -e .
9. 优缺点分析
pipenv集成了pip,virtualenv两者的功能 , 且完善了两者的一些缺陷。支持
Python2和Python3, 在各个平台的命令都是一样的。类似
npm, 容易迁移 , 便于项目内部协同工作各个地方使用了哈希校验 , 无论安装还是卸载包都十分安全 , 且会自动公开安全漏洞。
通过加载
.env文件简化开发工作流程。Bug很多 , 确实比较年轻 , 安装的流程有些让人困惑 , 不像pip这么直接好理解
参考链接
Python多环境管理神器(pipenv ) - doublexi - 博客园