Python多環境管理神器(pipenv)

doublexi發表於2022-01-12

pipenv

參考官網:https://pipenv.pypa.io/

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)" 

參考:https://blog.csdn.net/swinfans/article/details/89305301

命令詳解:

$ 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@ops-130 data]# mkdir myproj10
[root@ops-130 data]# cd myproj10/
[root@ops-130 myproj10]# ls
[root@ops-130 myproj10]# pipenv install

上面的命令會自動在~/.local/share/virtualenvs/目錄下建立虛擬環境目錄,

名字為一個當前目錄名加一串隨機字串的虛擬環境目錄。這裡是myproj10-740tHe3W

建立過程如下圖:

clipboard

下面多了兩個檔案,為Pipfile和Pipfile.lock,用於存放依賴包名的檔案。

類似php裡的composer.json和composer.lock。

[root@ops-130 myproj10]# ls
Pipfile  Pipfile.lock

檢視虛擬環境

[root@ops-130 myproj10]# pipenv --venv
/root/.virtualenvs/myproj10-740tHe3W

我們的虛擬環境目錄在/root/.virtualenvs/下面,是因為我們之前設定過環境變數

export WORKON_HOME=$HOME/.virtualenvs 

啟用虛擬環境:

cd /data/myproj10
pipenv shell

啟用後如下圖:

clipboard

注意:上面啟用虛擬環境的時候,出現了這麼一個告警:

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

如下圖:

clipboard

退出虛擬環境:exit

((myproj10) ) [root@ops-130 myproj10]# exit
exit
[root@ops-130 myproj10]#

剛建立好虛擬環境的時候,會自動進入虛擬環境,並且此時是沒有字首顯示,此時需要用exit退出。

當後面用pipenv shell啟用的時候,會顯示字首,此時可以用exit退出,也可以使用deactivate退出。

clipboard

刪除虛擬環境

[root@ops-130 myproj10]# pipenv --rm 
Removing virtualenv (/root/.virtualenvs/myproj10-740tHe3W)...

2.2、建立虛擬環境的多種方式

pipenv建立虛擬環境有多種方式,這裡總結一下:

方式一:指定直譯器建立虛擬環境

# 建立虛擬環境
pipenv --three
# 或者
pipenv --python 3.9

這種方式是指定python直譯器,並建立虛擬環境。

它會在當前目錄生成Pipfile,不會生成Pipfile.lock

這種方式建立虛擬環境後,會自動進入虛擬環境,但是進入後也不會顯示字首

clipboard

方式二:安裝所有依賴時建立虛擬環境

# 建立虛擬環境
pipenv install

這種方式是在安裝依賴包的同時建立虛擬環境。

因為pipenv install,就是根據Pipfile來安裝所有依賴,類似npm install

如果當前目錄沒有Pipfile,它就會自動建立Pipfile並建立虛擬環境。

因為這種方式它已經在安裝所有依賴了,所以不僅會建立Pipfile,也會建立Pipfile.lock檔案。

同時,它建立虛擬環境後,也會自動進入環境,但是也不會顯示字首。

如下圖:

clipboard

方式三:啟用時建立虛擬環境

# 啟用,如果環境不存在,則建立虛擬環境並啟用
pipenv shell

這個命令主要用於啟用環境,但是如果環境不存在,則會先建立虛擬環境,並同時啟用虛擬環境。

這種方式因為使用了pipenv shell啟用了,所以建立虛擬環境後,也會自動進入虛擬環境,並啟用。

會顯示虛擬環境字首。

如下圖:

clipboard

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@ops-130 aaa]# pipenv --where
/data/myproj10

定位虛擬環境目錄,即virtualenv目錄

[root@ops-130 aaa]# pipenv --venv
/root/.virtualenvs/myproj10-740tHe3W

定位Python直譯器:

[root@ops-130 aaa]# pipenv --py
/root/.virtualenvs/myproj10-740tHe3W/bin/python

如下圖:

clipboard

3、pipenv包管理

安裝依賴包:

安裝相關依賴包,並加入到Pipfile

pipenv install flask

它會在當前環境安裝flask依賴包,並記錄flask包名以及版本資訊,記錄到Pipfile裡。

如果安裝的時候,沒有指定包名,預設是最新的,會記錄為“*”

注意:Pipfile只會記錄你install裡指定的包,但是這個flask包本身所依賴的包不會記錄,

但是所有的依賴詳情都會記錄到Pipfile.lock中。

clipboard

Pipfile.lock類似如下:

clipboard

檢視目前安裝的庫及其依賴關係

pipenv graph

如下圖:這是所有的完整依賴關係,這些會記錄在Pipfile.lock中。

clipboard

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.0

Pipenv 將安裝 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中移除。

clipboard

解除安裝當前環境所有包:

# 從虛擬環境中移除所有已安裝的包,但 Pipfile.lock 檔案不受影響
pipenv uninstall --all

解除安裝開發包:

# 從虛擬環境中解除安裝所有開發包,並從 Pipfile 檔案中移除這些包
pipenv uninstall –all-dev

更新依賴包:

檢視所有需要更新的包:

pipenv update --outdated

如下圖:

clipboard

更新指定包:

pipenv update <包名>

更新所有包:

pipenv update

檢查安全漏洞:

pipenv check  # 檢查安全漏洞

它可能會檢查出很多錯誤,其實如果不影響你使用,你可以直接忽略掉。強迫症患者也可以一個一個問題去解決。

比如如下問題:

clipboard

修改pipenv的映象源

可以修改當前目錄下Pipfile檔案,將[source]下的url屬性改成國內的源即可:

[[source]]
url = "https://mirrors.aliyun.com/pypi/simple"
verify_ssl = true
name = "pypi"

3、環境部署

使用pipenv進行多環境部署

dev與正式環境區分安裝。

當你想要一個包只在開發環境使用,等生產部署的時候,不需要該安裝包,你可以這樣指定環境安裝。

# 把django安裝在開發環境
pipenv install django --dev

安裝如下圖

clipboard

安裝完成後,檢視Pipfile檔案:

會發現,pipenv已經將安裝包區分開來了。

[dev-packages] 裡記錄的--dev開發環境安裝的包

[package] 裡記錄的是沒有加環境引數,預設就是正式環境的包。

clipboard

那麼等到你真正遷移到生產環境部署的時候,就只需要這麼做:

pipenv install

這樣預設是隻安裝[package] 裡的安裝包的,會自動過濾掉[dev-packages] 裡的包。

讓生產環境變得更加純淨,避免有多餘的包。

如下:這是直接pipenv install的,裡面是沒有django包的

clipboard

如果你要遷移到開發環境,只需要這麼做:

pipenv install --dev

它就會把[dev-packages] 裡的包也一起安裝上了。

如下:

這是使用了--dev引數的,看到已經把djiango安裝上了。

clipboard

4、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檔案
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 檔案不是最新的時候導致構建失敗,而不是生成一個新的。

5、相容requirements.txt

之前我們的pip工具可以從requierments.txt檔案中匯入依賴包。

在pipenv,用下面的命令就可以將Pipfile和Pipfile.lock檔案裡面的包匯出為requirements.txt檔案。

# 將Pipfile裡的全部包匯出到requirements.txt
pipenv lock -r > requirements.txt

內容如下:

clipboard

可以選擇只匯出開發環境的包:

# 只匯出開發環境的包
pipenv lock -r --dev-only > requirements.txt

如下圖:

clipboard

匯出開發環境+ 預設的環境的包:

# dev環境和default環境的包都會匯出
pipenv lock -r --dev > requirements.txt

如下圖:

clipboard

也可以使用底層pip的命令匯出:

pipenv run pip freeze > requirements.txt

如下圖:

clipboard

匯入requirements.txt

匯出為requirements.txt後,可以通過pip匯入,也可以通過pipenv匯入。

# 通過pip匯入
pip install -r requirements.txt
# 通過pipenv匯入
pipenv install -r requirements.txt

6、虛擬環境中執行命令:

啟動shell執行

正常來說,如果想要讓命令執行在虛擬環境,需要啟動一個虛擬環境的shell,否則命令還是在系統環境下執行的,如下:

pipenv shell

如下圖:

clipboard

使用run執行:

如果不想啟動shell,而是直接在虛擬環境中執行命令,可以使用run:

# pipenv run <命令>
pipenv run python --version

如下圖:

clipboard

部署專案的時候,你也可以不進入虛擬環境的方式執行專案:

pipenv run python xxx.py

7、環境變數:(.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 shell

Pipfile引用環境變數:

在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 .

更多pipenv的用法,請參考官網:https://pipenv.pypa.io/en/latest/

8、優缺點分析:

1、pipenv整合了pip,virtualenv兩者的功能,且完善了兩者的一些缺陷。

2、支援Python2 和 Python3,在各個平臺的命令都是一樣的。

3、類似npm,容易遷移,便於專案內部協同工作

4、各個地方使用了雜湊校驗,無論安裝還是解除安裝包都十分安全,且會自動公開安全漏洞。

5、通過載入.env檔案簡化開發工作流程。

6、Bug 很多,確實比較年輕,安裝的流程有些讓人困惑,不像 pip 這麼直接好理解


參考引用:

https://blog.csdn.net/swinfans/article/details/89305301

https://pipenv.pypa.io/en/latest/

相關文章