1. 程式人生 > >Requests庫作者另一神器Pipenv的用法

Requests庫作者另一神器Pipenv的用法

python3 環境變量 six 切換 style 模式 添加 .profile bin

前言

我們在運行 Python 項目的時候經常會遇到一些版本問題,例如 A 項目依賴於 Django 1.5,而 B 項目又依賴 Django 2.0,而我們的系統卻只有一個 Python 解釋器,我們所有的包都被裝在了 Python 安裝目錄的 site-packages 目錄下,所以 Django 只能是某個特定的版本,所以這樣就會導致運行的時候導致 A 或 B 項目出現兼容問題。為了解決這個問題,我們可能會使用 virtualenv 來為項目創建一套獨立的 Python 運行環境,或者我們可能會使用 Docker 容器來實現不同項目的隔離運行,但總的來說,它們使用起來其實並沒有那麽方便。另外在進行 Python 包管理時,requirements.txt 這樣的包依賴標識文件也顯得很雞肋,在某些情況下可能會帶來一些麻煩。為了解決這些問題,一個更加使用方便的包管理工具誕生了,叫做 Pipenv,接下來就讓我們一起來了解一下它的用法。

簡介

Pipenv,它的項目簡介為 Python Development Workflow for Humans,是 Python 著名的 requests 庫作者 kennethreitz 寫的一個包管理工具,它可以為我們的項目自動創建和管理虛擬環境並非常方便地管理 Python 包,現在它也已經是 Python 官方推薦的包管理工具。

Pipenv 我們可以簡單理解為 pip 和 virtualenv 的集合體,它可以為我們的項目自動創建和管理一個虛擬環境。virtualenv 在使用時我們需要手動創建一個虛擬環境然後激活,Pipenv 會自動創建。另外我們之前可能使用 requirements.txt 文件來標識項目所需要的依賴,但是這樣會帶來一些問題,如有的 requirements.txt 中只是將庫名列出來了,沒有嚴格指定版本號,這樣就可能會導致不同時間安裝的庫版本是不同的,如 requirements.txt 文件中對 Django 的依賴只寫了一個 django,可能在 2016 年的時候運行安裝會安裝 Django 的 1.x 版本,到了 2017 年就會安裝 Django 的 2.x 版本,所以可能導致一些麻煩。為了解決這個問題,Pipenv 直接棄用了 requirements.txt,會同時它會使用一個叫做 Pipfile 和 Pipfile.lock 的文件來管理項目所需的依賴包,而不再是簡單地使用 requirements.txt 文件來記錄項目所需要的依賴。

總的來說,Pipenv 可以解決如下問題:

  • 我們不需要再手動創建虛擬環境,Pipenv 會自動為我們創建,它會在某個特定的位置創建一個 virtualenv 環境,然後調用 pipenv shell 命令切換到虛擬環境。
  • 使用 requirements.txt 可能會導致一些問題,所以 Pipenv 使用 Pipfile 和 Pipfile.lock 來替代之,而且 Pipfile 如果不存在的話會自動創建,而且在安裝、升級、移除依賴包的時候會自動更新 Pipfile 和 Pipfile.lock 文件。
  • 廣泛使用 Hash 校驗,保證安全性。
  • 可以更清晰地查看 Python 包及其關系,調用 pipenv graph 即可呈現,結果簡單明了。
  • 可通過自動加載 .env 讀取環境變量,簡化開發流程。

安裝

本文內容基於 Python 3.6 說明,默認的 Python 解釋器命令為 python3,包管理工具命令為 pip3

Pipenv 是基於 Python 開發的包,所以可以直接用 pip 來安裝,命令如下:

pip3 install pipenv

另外還有多種安裝方式,如 Pipsi、Nix、Homebrew,安裝方式可以參考:http://pipenv.readthedocs.io/en/latest/#install-pipenv-today。

基本使用

首先我們可以新建一個項目,例如叫做 PipenvTest,然後新建一個 Python 腳本,例如叫 main.py,內容為:

import django
print(django.get_version())

直接用系統的 Python3 運行此腳本:

python3 main.py

結果如下:

1.11

我們可以看到系統安裝的 Django 版本是 1.11。但是我們想要本項目基於 Django 2.x 開發,當然我們可以選擇將系統的 Django 版本升級,但這樣又可能會影響其他的項目的運行,所以這並不是一個好的選擇。為了不影響系統環境的 Django 版本,所以我們可以用 Pipenv 來創建一個虛擬環境。

在該目錄下,輸入 pipenv 命令即可查看命令的完整用法:

Usage: pipenv [OPTIONS] COMMAND [ARGS]...
 
Options:
  --update         Update Pipenv & pip to latest.
  --where          Output project home information.
  --venv           Output virtualenv information.
  --py             Output Python interpreter information.
  --envs           Output Environment Variable options.
  --rm             Remove the virtualenv.
  --bare           Minimal output.
  --completion     Output completion (to be evald).
  --man            Display manpage.
  --three / --two  Use Python 3/2 when creating virtualenv.
  --python TEXT    Specify which version of Python virtualenv should use.
  --site-packages  Enable site-packages for the virtualenv.
  --jumbotron      An easter egg, effectively.
  --version        Show the version and exit.
  -h, --help       Show this message and exit.
 
 
Usage Examples:
   Create a new project using Python 3.6, specifically:
   $ pipenv --python 3.6
 
   Install all dependencies for a project (including dev):
   $ pipenv install --dev
 
   Create a lockfile containing pre-releases:
   $ pipenv lock --pre
 
   Show a graph of your installed dependencies:
   $ pipenv graph
 
   Check your installed dependencies for security vulnerabilities:
   $ pipenv check
 
   Install a local setup.py into your virtual environment/Pipfile:
   $ pipenv install -e .
 
Commands:
  check      Checks for security vulnerabilities and against PEP 508 markers
             provided in Pipfile.
  graph      Displays currently–installed dependency graph information.
  install    Installs provided packages and adds them to Pipfile, or (if none
             is given), installs all packages.
  lock       Generates Pipfile.lock.
  open       View a given module in your editor.
  run        Spawns a command installed into the virtualenv.
  shell      Spawns a shell within the virtualenv.
  uninstall  Un-installs a provided package and removes it from Pipfile.
  update     Uninstalls all packages, and re-installs package(s) in [packages]
             to latest compatible versions.

接下來我們首先驗證一下當前的項目是沒有創建虛擬環境的,調用如下命令:

pipenv --venv

結果如下:

No virtualenv has been created for this project yet!

這說明當前的項目尚未創建虛擬環境,接下來我們利用 Pipenv 來創建一個虛擬環境:

pipenv --three

or 

pipenv --python 3.6

都可以創建一個 Python3 的虛擬環境,--three 代表創建一個 Python3 版本的虛擬環境,--python 則可以指定特定的 Python 版本,當然 --two 則創建一個 Python2 版本的虛擬環境,但前提你的系統必須裝有該版本的 Python 才可以。

執行完畢之後,樣例輸出如下:

Warning: the environment variable LANG is not set!
We recommend setting this in ~/.profile (or equivalent) for proper expected behavior.
Creating a virtualenv for this project…
#Pipenv 利用 /usr/local/bin/python3 作為 virtualenv 的解釋器
Using /usr/local/bin/python3 to create virtualenv…

?Running virtualenv with interpreter /usr/local/bin/python3
Using base prefix /usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6

New python executable in /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python3.6
Also creating executable in /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python

Installing setuptools, pip, wheel...done.
Virtualenv location: /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E

這裏顯示 Pipenv 利用 /usr/local/bin/python3 作為 virtualenv 的解釋器,然後在 /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin 目錄下創建了一個新的 Python3 解釋器,同時還創建了兩個可執行文件別名 python3.6 和 python,另外我們還可以發現目錄下多了一個 Pipfile 文件,這時虛擬環境就創建完成了。

我們切換到 PipenvTest-VSTVh89E/bin 目錄查看一下文件結構:
可以看到這裏面包含了 pip、pip3、pip3.6、python、python3、python3.6 等可執行文件,實際上目錄結構和使用 virtualenv 時是完全一樣的,只不過文件夾的位置不同而已。

接下來我們可以切換到該虛擬環境下執行命令,執行如下命令即可:

pipenv shell

執行完畢之後樣例輸出如下:

Spawning environment shell (/bin/zsh). Use exit to leave.
source /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/activate                                                            
CQC-MAC% source /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/activate
(PipenvTest-VSTVh89E) CQC-MAC%

實際上這也和 virtualenv 激活的流程一樣,也是調用了類似 source venv/bin/activate 方法將這個路徑加到全局環境變量最前面,這樣就會優先調用該路徑下的 python、python3、python3.6 可執行文件了。

這時候我們會發現命令行的樣子就變了,前面多了一個 (PipenvTest-VSTVh89E) 的標識,代表當前我們已經切換到了虛擬環境下。

這時我們用 which 或 where 命令查看一下 Python 可執行文件的路徑,命令如下:

(PipenvTest-VSTVh89E) CQC-MAC% which python3
/Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python3
(PipenvTest-VSTVh89E) CQC-MAC% which python3.6
/Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python3.6
(PipenvTest-VSTVh89E) CQC-MAC% which python
/Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python

可以發現當前的 Python 可執行路徑都被切換到了 PipenvTest-VSTVh89E/bin 目錄下,調用的是虛擬環境中的 Python 解釋器,這時我們重新執行剛才的腳本,命令如下:

(PipenvTest-VSTVh89E) CQC-MAC% python3 main.py

這時我們可以發現報了如下錯誤:

Traceback (most recent call last):
  File "main.py", line 1, inimport django
ModuleNotFoundError: No module named django

這其實是因為新的虛擬環境沒有安裝任何的 Python 第三方包,實際上如果直接使用 virtualenv 時也是這樣的結果。這是因為新的虛擬環境是一個全新的 Python 環境,它默認只包含了 Python 內置的包以及 pip、wheel、setuptools 包,其他的第三方包都沒有安裝。

這時我們可以使用 Pipenv 來安裝 django 包,命令如下:

pipenv install django

運行後輸出結果如下:

Installing django…
Collecting django
  Downloading Django-2.0.2-py3-none-any.whl (7.1MB)
Collecting pytz (from django)
  Downloading pytz-2018.3-py2.py3-none-any.whl (509kB)
Installing collected packages: pytz, django
Successfully installed django-2.0.2 pytz-2018.3
 
Adding django to Pipfiles [packages]…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (e101fb)!

如果有這樣的輸出結果就代表成功安裝了 Django,可以看到此時安裝的 Django 版本為 2.0,代表我們的虛擬環境成功安裝了 Django 2.0 版本。

同時我們還註意到它輸出了一句話叫做 Updated Pipfile.lock,這時我們可以發現項目路徑下又生成了一個 Pipfile.lock 文件,內容如下:

可以看到裏面標識了 Python 環境基本信息,以及依賴包的版本及 hashes 值。

另外我們還可以註意到 Pipfile 文件內容也有更新,[packages] 部分多了一句 django = "*",標識了本項目依賴於 Django,這個其實類似於 requirements.txt 文件。

那麽到這裏有小夥伴可能就會問了, Pipfile 和 Pipfile.lock 有什麽用呢?

Pipfile 其實一個 TOML 格式的文件,標識了該項目依賴包的基本信息,還區分了生產環境和開發環境的包標識,作用上類似 requirements.txt 文件,但是功能更為強大。Pipfile.lock 詳細標識了該項目的安裝的包的精確版本信息、最新可用版本信息和當前庫文件的 hash 值,顧明思義,它起了版本鎖的作用,可以註意到當前 Pipfile.lock 文件中的 Django 版本標識為 ==2.0.2,意思是當前我們開發時使用的就是 2.0.2 版本,它可以起到版本鎖定的功能。

舉個例子,剛才我們安裝了 Django 2.0.2 的版本,即目前(2018.2.27)的最新版本。但可能 Django 以後還會有更新,比如某一天 Django 更新到了 2.1 版本,這時如果我們想要重新部署本項目到另一臺機器上,假如此時不存在 Pipfile.lock 文件,只存在 Pipfile文件,由於 Pipfile 文件中標識的 Django 依賴為 django = "*",即沒有版本限制,它會默認安裝最新版本的 Django,即 2.1,但由於 Pipfile.lock 文件的存在,它會根據 Pipfile.lock 來安裝,還是會安裝 Django 2.0.2,這樣就會避免一些庫版本更新導致不兼容的問題。

請記住:任何情況下都不要手動修改 Pipfile.lock 文件!

好,接下來我們再回歸正題,現在已經安裝好了 Django 了,那麽我們重新運行此腳本便可以成功輸出 Django 版本信息了:

(PipenvTest-VSTVh89E) CQC-MAC% python3 main.py

結果如下:

2.0.2

這樣我們就成功安裝了 Django 2.x 了,和系統的 Django 1.11 沒有任何沖突。

在此模式的命令行下,我們就可以使用虛擬環境下的 Python 解釋器,而且所安裝的依賴包對外部系統沒有任何影響,而且使用 Pipfile 和 Pipfile.lock 來管理項目的依賴更加方便和健壯。

如果想要退出虛擬環境,只需要輸入 exit 命令即可:

(PipenvTest-VSTVh89E) CQC-MAC% exit
?  PipenvTest python3 main.py 
1.11

輸入退出命令之後,我們重新再運行此腳本,就會重新使用系統的 Python 解釋器,Django 版本又重新回到了 1.11。

由此可以看來,有了 Pipenv,我們可以使用 Pipfile 和 Pipfile.lock 來方便地管理和維護項目的依賴包,而且可以實現虛擬環境運行,避免了包沖突問題,可謂一舉兩得。

常用命令

上文我們介紹了 Pipenv 的基本操作,下面我們再介紹一下它的一些常用命令。

虛擬環境路徑

我們可以使用 --venv 參數來獲得虛擬環境路徑:

pipenv --venv

樣例輸出如下:

/Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E

可見這個路徑是一個標準的路徑,Pipenv 會把虛擬環境統一放到 virtualenvs 文件夾下,而不是本項目路徑下。

Python 解釋器路徑

要獲取虛擬環境 Python 解釋器路徑,可以使用 --py 參數:

pipenv --py

樣例輸出如下:

/Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python

加載系統 Python 包

默認情況下,新創建的虛擬環境是不包含任何第三方包的,但我們也可以開啟加載系統 Python 包功能,使用 --site-packages 即可:

pipenv --site-packages

這樣創建的虛擬環境便可以使用系統已安裝的 Python 包了。

開啟虛擬環境

要開啟虛擬環境只需要執行如下命令:

pipenv shell

這樣就可以進入虛擬環境,此時運行的 python、python3 命令都是虛擬環境下的。

安裝 Python 包

安裝 Python 包我們不再需要 pip 來安裝,直接使用 Pipenv 也可安裝,如安裝 requests,命令如下:

pipenv install requests

安裝完成之後會同時更新項目目錄下的 Pipfile 和 Pipfile.lock 文件。

有時候一些 Python 包是僅僅開發環境需要的,如 pytest,這時候我們通過添加 --dev 參數即可,命令如下:

pipenv install pytest --dev

這時候,pytest 的依賴便會記錄在 Pipfile 的 [dev-packages] 區域:

[dev-packages]
pytest = "*"

獲取包依賴

我們可以使用命令來清晰地呈現出當前安裝的 Python 包版本及之間的依賴關系,命令如下:

pipenv graph

樣例結果如下:

Django==2.0.2
  - pytz [required: Any, installed: 2018.3]
pytest==3.4.1
  - attrs [required: >=17.2.0, installed: 17.4.0]
  - pluggy [required: <0.7,>=0.5, installed: 0.6.0]
  - py [required: >=1.5.0, installed: 1.5.2]
  - setuptools [required: Any, installed: 38.5.1]
  - six [required: >=1.10.0, installed: 1.11.0]
requests==2.18.4
  - certifi [required: >=2017.4.17, installed: 2018.1.18]
  - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
  - idna [required: <2.7,>=2.5, installed: 2.6]
  - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]

可以看到結果非常清晰,Django 當前安裝了 2.0.2版本,依賴於 pytz 任何版本,已經安裝了 2018.3 版本;pytest 已經安裝了 3.4.1 版本,依賴 attrs>=17.2.0 版本,已經安裝了 17.4.0 版本,另外還依賴 pluggy、py、setuptools、six 這些庫。總之包的依賴關系一目了然。

卸載 Python 包

卸載 Python 包也非常簡單,如卸載 requests 包,命令如下:

pipenv uninstall requests

卸載完成之後,Pipfile 和 Pipfile.lock 文件同樣會更新。

如果要卸載全部 Python 包,可以添加 --all 參數:

pipenv uninstall --all

產生 Pipfile.lock

有時候可能 Pipfile.lock 文件不存在或被刪除了,這時候我們可以使用如下命令生成:

pipenv lock

以上便是一些常用的 Pipenv 命令,如果要查看更多用法可以參考其官方文檔:https://docs.pipenv.org/#pipenv-usage。

結語

本文介紹了 Pipenv 的基本用法,作為 pip 和 virtualenv 的結合體,我們可以利用它更方便地創建和管理 Python 虛擬環境,還可以用更加科學的方式管理 Python 包,一舉兩得。

嗯,是時候拋棄 virtualenv 和 pip 了!

Requests庫作者另一神器Pipenv的用法