Python 開發中一般會使用 virtualenv
pip
管理專案執行環境與依賴。在建立一個新專案時先使用 virtualenv
建立一個虛擬執行環境,然後使用 pip
安裝依賴,最後使用 pip freeze > requirements.txt
記錄專案依賴。這個過程中會遇到一些問題:
- 版本資訊沒有儲存
- 升級依賴包時需要先檢視
requirements.txt
- 開發環境與生產環境依賴區分
解決上述問題一般的做法是生成多個 requirements.txt
,比如:requirements-dev.txt
、requirements-prod.txt
並記錄好依賴版本資訊,或者選擇 Pipenv: Python Dev Workflow for Humans 。
從名字可以很直觀的看出 pipenv
= pip
+ virtualenv
。
在開發中使用 pipenv
在專案開發過程中使用 pipenv
體驗基本與 pip
一致,而且由於 pipenv
也會同時管理虛擬環境,體驗上流程更順滑。pipenv
使用 Pipfile
與 Pipfile.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 install
或 pipenv 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.2
到 2.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
都會更新 pipfile
與 pipfile.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 修復了問題也只能在新版本中解決,因此短期內如果有跨平臺需求還需要先確定是否正常。