Pipenv 快速入門

TomCzHen發表於2019-04-03

A Better Pip Workflow™

Python 開發中一般會使用 virtualenv pip 管理專案執行環境與依賴。在建立一個新專案時先使用 virtualenv 建立一個虛擬執行環境,然後使用 pip 安裝依賴,最後使用 pip freeze > requirements.txt 記錄專案依賴。這個過程中會遇到一些問題:

  • 版本資訊沒有儲存
  • 升級依賴包時需要先檢視requirements.txt
  • 開發環境與生產環境依賴區分

解決上述問題一般的做法是生成多個 requirements.txt ,比如:requirements-dev.txtrequirements-prod.txt 並記錄好依賴版本資訊,或者選擇 Pipenv: Python Dev Workflow for Humans

從名字可以很直觀的看出 pipenv = pip + virtualenv

在開發中使用 pipenv

在專案開發過程中使用 pipenv 體驗基本與 pip 一致,而且由於 pipenv 也會同時管理虛擬環境,體驗上流程更順滑。pipenv 使用 PipfilePipfile.lock 來管理依賴資訊,Pipfile.lock 會根據安裝的依賴包記錄 hash 校驗值與版本資訊。

建立虛擬環境

在新建專案目錄下可以通過以下方式建立虛擬環境:

$ pipenv --python 3.6
複製程式碼
$ pipenv --python /path/to/python
複製程式碼
$ pipenv install requests --python 3.6
複製程式碼

注意:如果沒有使用 --python 引數指定 Python 版本則會使用預設的 Python 版本建立,如果想指定預設 Python 版本可以通過環境變數 PIPENV_DEFAULT_PYTHON_VERSION 配置,可以設定為 Python 版本號:3.6.8 或 Python 直譯器程式路徑。

如果需要虛擬執行環境目錄指定在專案目錄下建立,有兩種方式可以實現:

  • 執行 pipenv 前先建立 .venv 目錄
$ mkdir .venv && pipenv install requests --python 3.6
複製程式碼
  • 配置 PIPENV_VENV_IN_PROJECT 環境變數
$ export PIPENV_VENV_IN_PROJECT=1
複製程式碼

如果想自定義這個目錄則需要通過環境變數 WORKON_HOME 來配置。

從現有專案建立虛擬環境

對於現有專案,可以區分為三種情況:

  • 沒有使用 pipenv

使用 pipenv install -r path/to/requirements.txt --python 3.6 來安裝依賴。

  • 有使用意向,但需要相容舊方式

通過 pipenv lock -r > requirements.txt 生成與 pip 相同格式的依賴管理檔案。

  • 已經在使用

根據需要可以使用 pipenv installpipenv sync。兩者都會根據 Pipfile 中的 Python 版本建立虛擬環境,使用指定的 PyPI 源,區別是 pipenv install 會根據 Pipfile 中的版本資訊安裝依賴包,並重新生成 Pipfile.lock;而 pipenv sync 會根據 Pipfile.lock 中的版本資訊安裝依賴包。

也就是 pipenv install 安裝的依賴包版本可能被更新,具體的機制在依賴包管理中進一步說明。

啟用虛擬環境

可以先啟用虛擬環境,再來執行 Python :

$ pipenv shell
複製程式碼

或者直接執行:

$ pipenv run python main.py
複製程式碼

在專案根目錄下有 .env 環境配置檔案時,啟用虛擬環境同時會載入 .env 檔案中的環境變數配置,如果不想使用這個功能可以通過配置 PIPENV_DONT_LOAD_ENV 變數來關閉它。

依賴包管理

pipenv安裝包的使用方式與 pip 基本一致,直接在專案目錄下執行 pipenv install request時 會安裝到虛擬環境目錄下,沒有虛擬環境則會建立後安裝。

安裝包

沒有指定版本資訊時,Pipfile 中不會註明版本,如果在新目錄中使用 pipenv install 直接安裝依賴包的最新版本。

$ pipenv install requests
複製程式碼

以下方式會指定為 1.2 或以上版本,但不會大於等於 2.0,使用pipenv install 安裝依賴時,如果新版本在 1.22.0 之間(不包含 2.0 版本)就會更新

$ pipenv install “requests~=1.2”
複製程式碼

更多的版本指定方式如下:

$ pipenv install "requests>=1.4"   # 版本號大於或等於 1.4.0
$ pipenv install "requests<=2.13"  # 版本號小於或等於 2.13.0
$ pipenv install "requests>2.19"   # 版本號大於 2.19.0
複製程式碼

如果僅僅在開發 環境下使用這個包,可以新增 --dev 引數安裝:

$ pipenv install ipython --dev
複製程式碼

更新包

  • 檢視有更新的包
$ pipenv update --outdated
複製程式碼
  • 更新所有依賴包
$ pipenv update
複製程式碼
  • 更新指定依賴包
$ pipenv update request
複製程式碼

注意:升級依賴包的版本時受到 Pipfile 中版本資訊限制,如果想安裝超出限制的版本,則需要執行 pipenv install <pkg> 安裝。

解除安裝包

$ pipenv uninstall requests
複製程式碼
  • 檢視依賴關係
$ pipenv graph
複製程式碼

安裝或解除安裝依賴包之後,pipenv 都會更新 pipfilepipfile.lock

配置 PyPi 映象源

pip 通常會使用 pip.conf 或者 --index-url 引數來配置 PyPI 映象源,pipenv 中有多種配置方式:

  • 使用環境變數 PIPENV_PYPI_MIRROR 配置。
$ export PIPENV_PYPI_MIRROR=https://mirrors.aliyun.com/pypi/simple/
複製程式碼
  • 使用專案中的 pipfile 檔案配置。

通過專案 pipfile 檔案中的 [[source]] 節也可以配置安裝源,並且只對該專案生效。

[[source]]
name = "pypi"
url = "https://mirrors.aliyun.com/pypi/simple/"
verify_ssl = true
...
複製程式碼

配合 pyenv 使用

Linux 和 macOS 下可以安裝 pyenv 配合使用,在使用 pipenv 時如果指定的 Python 版本沒有安裝,就會呼叫 pyenv 進行編譯安裝。

首先請參考 pyenv: Common build problems - Prerequisites 安裝好編譯依賴。

然後根據 Simple Python Version Management: pyenv - Installation 安裝好 pyenv

注意:Windows 使用者請手動下載 Python 安裝包安裝,通過 pipenv --python X:\Python\...\python.exe 指定 Python 版本,如果想編譯安裝請自行解決

配置 pyenv

可以根據需要配置原始碼快取與編譯臨時檔案路徑,解決因為網路問題無法下載原始碼包,或者 /tmp 分割槽空間不足造成編譯安裝失敗。

  • 原始碼包快取

新增快取目錄,然後將原始碼包存放到快取目錄,並且編譯失敗時不會重新下載原始碼包。

$ mkdir -p $(pyenv root)/cache
複製程式碼
  • 臨時檔案目錄

預設使用系統臨時檔案路徑 /tmp,指定其他路徑為臨時檔案目錄。

$ mkdir ~/tmp
$ export TMPDIR="$HOME/tmp"
複製程式碼
  • 有些第三方包工具比如 PyInstaller 需要 CPython 以 --enable-shared 引數編譯
$ env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.6.8
複製程式碼

在部署中使用 pipenv

為了保證部署時安裝的依賴版本與釋出一致,不能使用 pipenv install 進行安裝,需要加上 --deploy 引數。

$ pipenv install --deploy
複製程式碼

如果不使用虛擬環境,還需要加上 --system 引數

$ sudo pipenv install --deploy --system
複製程式碼

在 Docker 中使用 pipenv

這裡給一個 Dockerfile 作為參考。

FROM python:3.6.8

ENV PIP_INDEX_URL https://mirrors.aliyun.com/pypi/simple/
RUN pip3 install pipenv --no-cache-dir

RUN set -ex && mkdir /app
WORKDIR /app

COPY Pipfile Pipfile
COPY Pipfile.lock Pipfile.lock
RUN set -ex && pipenv install --deploy --system

COPY . /app
EXPOSE 8888
CMD python3 main.py
複製程式碼

也可以先構建一個 Base Image ,然後在構建應用映象時使用,假設構建的 Base Image tag 為 tomczhen/python-pipenv-base:3.6.8

  • Base Image Dockerfile
FROM python:3.6.8

ENV PIP_INDEX_URL https://mirrors.aliyun.com/pypi/simple/
RUN pip3 install pipenv --no-cache-dir

RUN set -ex && mkdir /app
WORKDIR /app

ONBUILD COPY Pipfile Pipfile
ONBUILD COPY Pipfile.lock Pipfile.lock
ONBUILD RUN set -ex && pipenv install --deploy --system
複製程式碼
  • Python Application Image Dockerfile
FROM tomczhen/python-pipenv-base:3.6.8

COPY . /app
EXPOSE 8888
CMD python3 main.py
複製程式碼

pipenv 的缺點

當然,pipenv 也有缺點存在。

lock 耗時

Lock updating is very slow · Issue #1914 · pypa/pipenv

這是一個代價問題。

由於需要根據依賴關係以及檔案 hash 來生成 Pipfile.lock,這個問題應該是無法在短期內徹底解決的,需要在 pipenv 帶來的依賴管理功能與速度上做一個權衡取捨。

目前的辦法是在安裝依賴時使用 pipenv install --skip-lock 來跳過生成/更新 Pipfile.lock,然後在需要時執行 pipenv lock 來生成/更新 Pipfile.lock

跨平臺問題

嚴格來說這並不算是 pipenv 的問題。

部分包在跨平臺時的依賴不同,比如 PyInstaller 可以在多個平臺使用,但僅在 Windows 上才依賴 pywin32 包,由於 Pipfile.lock 是根據安裝的包生成的,所以會造成跨平臺時安裝依賴失敗。

根據 Problem with Pipfile and system specific packages · Issue #1575 · pypa/pipenv 中的討論看,即便 pywin32 修復了問題也只能在新版本中解決,因此短期內如果有跨平臺需求還需要先確定是否正常。