分类
联系方式
  1. 新浪微博
  2. E-mail

Pipenv

背景

Python 项目依赖管理是个麻烦事。

virtualenv 部分解决了这个问题,让项目所依赖的库版本能够彼此隔离。

但不同项目对 Python 版本还是有要求的,有的不能高了,有的不能低了,这部分问题没有解决。

Pipenv 是一个比较新的 Python 项目依赖管理工具,能够解决这些问题。

介绍

Pipenv是一个旨在为Python世界带来所有打包世界中最好的项目。它将Pipfile、pip和virtualenv整合为一个单一的工具链。它具有非常漂亮的终端颜色。在我们的世界里,Windows是一流的公民。

它为你的项目自动创建和管理一个虚拟环境,并在你安装/卸载软件包时从你的Pipfile中添加/删除软件包。锁定命令会生成一个锁定文件(Pipfile.lock)。

Pipenv 是我目前在用的 Python 项目依赖管理工具,最大的好处是除了能指定依赖的版本,也能指定 Python 版本。简化了在不同机器上搭建环境的难度,非常好用。

安装方式

$ pip install --user pipenv

pipfile

pipfile 跟前端的 package.json、Dart 的 pubspec.yaml 一样,都是描述项目依赖的配置文件。pipfile.lock 则是根据 pipfile进行依赖解析,最终将各个库的确切版本信息进行固定。有了 pipfile.lock,能够保证在不同机器上以完全相同的依赖库版本运行、构建。pipfile 使用 TOML 格式标准。

一个典型的 pipfile 文件长这样:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"


[dev-packages]
pytest = "*"

主要分为 3 个部分:

  • source:指定使用的 Python 源,可以指定多个
  • packages:项目的运行时依赖
  • dev-packages:项目的开发时依赖,比如单测库

建议将 pipfile 和 pipfile.lock 都加入版本管理工具跟踪。

使用方式

基础使用方式

进入目标项目:

$ cd myproject

如果项目中存在 pipenv,则直接进行安装:

$ pipenv install

如果是一个非 pipenv 项目,可以直接安装所需依赖,pipenv 会自动创建:

$ pipenv install requests

之后通过下面命令进入虚拟环境:

$ pipenv shell

依赖升级

找出过时依赖:

$ pipenv update --outdated

自动升级所有依赖:

$ pipenv update

只升级某个依赖:

 $ pipenv update <pkg>

requirements.txt

如果项目包含 requirements.txt,在执行 pipenv install 的时候,pipenv 会自动把 requirements.txt 中的依赖添加到 pipfile 当中。

也可以通过下面命令手动指定 requirements.txt:

$ pipenv install -r path/to/requirements.txt

添加依赖

通过下面命令添加依赖:

$ pipenv install requests

添加指定版本的依赖:

$ pipenv install requests~=1.2

还支持指定版本范围:

# will install a version equal or larger than 1.4.0
$ pipenv install "requests>=1.4"

# will install a version equal or lower than 2.13.0
$ pipenv install "requests<=2.13"

# will install 2.19.1 but not 2.19.0
$ pipenv install "requests>2.19"

固定 Python 版本

这是我喜欢 pipenv 的一点,就是能固定所使用的 Python 版本,这对于运行网上的开源项目来说太重要了。

具体方式是在 pipfile 中添加一个 [requires] 小结,在里面写入版本。

关于 Python 的版本好,可以使用两位版本如 3.5、3.6,也可以使用三位版本号。

可以在 pipenv 中通过命令指定:

# Use Python 3
$ pipenv --python 3

# Use Python3.6:
$ pipenv --python 3.6

# Use Python 2.7.14
$ pipenv --python 2.7.14

也可以在 pipfile 的 requires 小节中指定:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true

[dev-packages]

[packages]

[requires]
python_version = "3.6"

使用技巧

指定私有源

如果使用私有源,配置方式:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[[source]]
url = "http://pypi.home.kennethreitz.org/simple"
verify_ssl = false
name = "home"

[dev-packages]

[packages]
requests = {version="*", index="home"}
maya = {version="*", index="pypi"}
records = "*"

指定 Pypi 镜像

pypi 源速度不够快,通常换用国内源速度会快一些,更换方式修改 pipfile:

$ pipenv install --pypi-mirror <mirror_url>

$ pipenv update --pypi-mirror <mirror_url>

$ pipenv sync --pypi-mirror <mirror_url>

$ pipenv lock --pypi-mirror <mirror_url>

$ pipenv uninstall --pypi-mirror <mirror_url>

清华源地址:https://pypi.tuna.tsinghua.edu.cn/simple

将虚拟环境安装到项目目录下

默认虚拟环境会安装到一个统一位置,这个位置由 WORKON_HOME 环境变量控制,通常在加目录下。

通过设置 PIPENV_VENV_IN_PROJECT 变量,能让 pipenv 在项目目录下创建虚拟环境,更符合我的使用习惯。

具体方式是在 shell 的初始化文件中添加:

export PIPENV_VENV_IN_PROJECT=1

安装 GPU 版本的 PyTorch

在 pipfile 中添加:

[[source]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu101"
verify_ssl = false

[packages]
torch = {version = "==1.8.1", index = "pytorch"}

问题记录

自动安装 Python 报错

我的系统版本是 macOS Big Sur 11.1。

执行下面命令,提示我自动安装 Python:

% pipenv --python 3.6 install

报错内容如下:

Warning: Python 3.6 was not found on your system...
Would you like us to install CPython 3.6.14 with Pyenv? [Y/n]: y
Installing CPython 3.6.14 with /usr/local/bin/pyenv (this may take a few minutes)...
✘ Failed... 
Something went wrong...
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.6.14.tar.xz...
-> https://www.python.org/ftp/python/3.6.14/Python-3.6.14.tar.xz
Installing Python-3.6.14...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk

BUILD FAILED (OS X 11.1 using python-build 20180424)

Inspect or clean up the working tree at /var/folders/sv/y5m7_9ps2d5cbpb928hq4_9c0000gn/T/python-build.20210807174958.8110
Results logged to /var/folders/sv/y5m7_9ps2d5cbpb928hq4_9c0000gn/T/python-build.20210807174958.8110.log

Last 10 log lines:
./Modules/posixmodule.c:8210:15: error: implicit declaration of function 'sendfile' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        ret = sendfile(in, out, offset, &sbytes, &sf, flags);
              ^
./Modules/posixmodule.c:10432:5: warning: code will never be executed [-Wunreachable-code]
    Py_FatalError("abort() called from Python code didn't abort!");
    ^~~~~~~~~~~~~
1 warning and 1 error generated.
make: *** [Modules/posixmodule.o] Error 1
make: *** Waiting for unfinished jobs....
1 warning generated.

Warning: The Python you just installed is not available on your PATH, apparently.

显然是没有安装成功。可以看到 Python 代码已经下载下来了,但是构建的时候报错了。pipenv 自动打印出了最后 10 条报错日志。 参考文章《macOS Big Sur使用Pyenv安装python失败》跟我遇到了一样的问题,最终是通过社区中提供的一个 patch 进行了修复:

CFLAGS="-I$(brew --prefix openssl)/include -I$(brew --prefix bzip2)/include -I$(brew --prefix readline)/include -I$(xcrun --show-sdk-path)/usr/include" LDFLAGS="-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib -L$(brew --prefix zlib)/lib -L$(brew --prefix bzip2)/lib" pyenv install --patch 3.5.6 < <(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)

嗯?发生了什么?翻看社区记录大体知道咋回事了:

macOS 升级到 Big Sur 之后,Darwin 升级到了 20.0.0,导致老版本 Python 源码识别不了(当时还没出这个系统版本),导致有宏 _POSIX_C_SOURCE 无法关闭,参考文章地址。从 3.7.8+ 之后才能正常识别,也就是说低于这一版本的构建都有问题。

那这个 patch 是个啥呢?核心变动是:

-  Darwin/1[0-9].*)
+  Darwin/[12][0-9].*)

-  Darwin/1@<:@0-9@:>@.*)
+  Darwin/@<:@[12]@:>@@<:@0-9@:>@.*)

主要是修改了版本的识别方式。 社区中有同学给出了一个更简便的命令组合方式:

pyenv install --patch 3.8.0 <<(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)

总结一下:如果在 Big Sur 及以上 macOS 版本安装 3.7.8 以下的老 Python,都需要带着这个 Patch,才能够成功构建 Python。 带着 Patch 安装的效果是这样的:

(base) maxiee@rmbp16 baby-steps-of-rl-ja-master % pyenv install --patch 3.6.14 <<(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.6.14.tar.xz...
-> https://www.python.org/ftp/python/3.6.14/Python-3.6.14.tar.xz
Installing Python-3.6.14...
patching file Misc/NEWS.d/next/macOS/2020-06-24-13-51-57.bpo-41100.mcHdc5.rst
patching file configure
Hunk #1 succeeded at 3375 (offset -51 lines).
patching file configure.ac
Hunk #1 succeeded at 495 (offset -15 lines).
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.6.14 to /Users/maxiee/.pyenv/versions/3.6.14

最终安装成功了。

安装 finRL 报错

原因是 scipy 没法 build https://github.com/scipy/scipy/issues/13361

原因在这里,貌似是 macOS 系统的问题:https://github.com/pypa/pipenv/issues/4564

解决方法是 export 一个变量再执行就好了:export SYSTEM_VERSION_COMPAT=1

网络资源

官方首页

The Hitchhiker's Guide to Python Pipenv & 虚拟环境

Pipenv: Python Dev Workflow for Humans