擁抱pipenv

作為一個希望把所有的事情都準備好的死理性派瓣赂,我對python的開發(fā)環(huán)境非常重視李命,不過python常常面臨生產(chǎn)環(huán)境和開發(fā)環(huán)境不一致侄非;或者在A處開發(fā)一陣子蕉汪,又放到B處開發(fā)的問題,之前的pip以及requirement有諸多問題逞怨,pipenv解決了這些問題者疤,并給出了最佳實踐方案。我專門編譯了一篇文章叠赦,希望能夠幫助到自己和大家:https://realpython.com/pipenv-guide/#package-distribution

pipenv所解決的問題

requirements.txt依賴管理的局限

如果我要使用 flask, 我會在requirements.txt里面寫上

flask

不過由于沒有指定版本驹马,因此在另一個環(huán)境通過pip install -r requirements.txt安裝依賴模塊時,會默認安裝最新版本的flask除秀,如果新版本向后兼容糯累,這當然是沒問題的。但是如果新版本不兼容舊的接口册踩,那么就出問題了:代碼無法在該環(huán)境運行泳姐。因此測試環(huán)境和生產(chǎn)環(huán)境的不一致出現(xiàn)了,同一份requirement.txt暂吉,結(jié)果出來2份不同的環(huán)境胖秒,這叫做 不確定構(gòu)建 (the build isn’t deterministic) 問題。
這時候借笙,可以考慮加上版本號扒怖,requirements.txt這么寫

flask==0.12.1

這么寫肯定可以了吧较锡?因為以后在新環(huán)境安裝pip install -r requirements.txt的時候业稼,用的是該指定版本,就不會發(fā)生跑不起來的情況蚂蕴。

是這樣嗎低散?不一定喲,我們再分析一下:因為flask本身還依賴于其他模塊骡楼,因此執(zhí)行pip install -r requirements.txt的時候熔号,flask使用的是0.12.1版本,但是它的依賴模塊可不一定相同鸟整。比如說flask依賴Werkzeug模塊引镊,而Werkzeug模塊的新版本有bug!

這時候,傳統(tǒng)的解決方式是使用pip freeze弟头, 它能給出當前環(huán)境下第三方模塊和所有依賴子模塊的版本號吩抓,因此在生產(chǎn)環(huán)境就可以確保使用與開發(fā)環(huán)境相同的模塊了。這樣我就可以把pip freeze的輸出寫入到requirement.txt:

click==6.7
Flask==0.12.1
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1

這或許解決了生產(chǎn)與開發(fā)環(huán)境不一致的問題赴恨,可是它又引入了一大坨新問題疹娶!

因為,也許Werkzeug==0.14.1隱藏了一個漏洞伦连,官方發(fā)布了0.14.2版本修復(fù)了該問題雨饺,那么我不僅需要及時下載更新模塊,還得去更新requirememts.txt文件惑淳。但是那么多模塊额港,我難道要把所有更新版本都記錄下來?事實上歧焦,我本不需要記錄那么多我不關(guān)心的模塊的版本锹安,我只想記錄自己關(guān)心的核心模塊版本。

這就出現(xiàn)了一個矛盾:<確定構(gòu)建>與<不記錄所有模塊版本>之間的矛盾倚舀。

多個項目依賴不同版本的子模塊

假如我有2個項目A和B叹哭,A依賴django==1.9,B依賴django==1.10痕貌。linux默認使用全局共享的依賴包风罩,因此當我在A和B項目間切換時,需要檢測--卸載--安裝django舵稠。

傳統(tǒng)的解決方式是使用virtual environment 超升,將項目A和B的第三包隔離開。python2目前有virtualenv方案哺徊,python3目前有venv方案室琢。

而pipenv也集成了虛擬環(huán)境管理的功能。

依賴分析

先解釋一下什么叫依賴分析落追,假如我有一個requirments.txt如下:

package_a
package_b

如果package_a依賴于package_c>=1.0盈滴,package_b依賴于同樣的package_c<=2.0, 那么在安裝a,b模塊時轿钠,就只能在(1.0巢钓,2.0)的中選擇package_c的版本,如果安裝工具有這種能力疗垛,就說它能做依賴分析症汹。

不過pip工具沒有這種依賴分析的功能。這時候只能通過在requirement.txt里面添加package_c的版本范圍才能解決問題贷腕,好傻:

package_c>=1.0,<=2.0
package_a
package_b

pipenv上場啦

例子

安裝, 我們默認是安裝的python3版本哈

$ pip install pipenv

在指定目錄下創(chuàng)建虛擬環(huán)境, 會使用本地默認版本的python

$ pipenv install

如果要指定版本創(chuàng)建環(huán)境背镇,可以使用如下命令咬展,當然前提是本地啟動目錄能找到該版本的python

$ pipenv --python 3.6

激活虛擬環(huán)境

$ pipenv shell

安裝第三方模塊, 運行后會生成Pipfile和Pipfile.lock文件

$ pipenv install flask==0.12.1

當然也可以不指定版本:

$ pipenv install numpy

如果想只安裝在開發(fā)環(huán)境才使用的包,這么做:

$ pipenv install pytest --dev

無論是生產(chǎn)環(huán)境還是開發(fā)環(huán)境的包都會寫入一個Pipfile里面瞒斩,而如果是用傳統(tǒng)方法挚赊,需要2個文件:dev-requirements.txt 和 test-requirements.txt。

接下來如果在開發(fā)環(huán)境已經(jīng)完成開發(fā)济瓢,如何構(gòu)建生產(chǎn)環(huán)境的東東呢荠割?這時候就要使用Pipfile.lock了,運行以下命令旺矾,把當前環(huán)境的模塊lock住, 它會更新Pipfile.lock文件蔑鹦,該文件是用于生產(chǎn)環(huán)境的,你永遠不應(yīng)該編輯它箕宙。

$ pipenv lock

然后只需要把代碼和Pipfile.lock放到生產(chǎn)環(huán)境嚎朽,運行下面的代碼,就可以創(chuàng)建和開發(fā)環(huán)境一樣的環(huán)境咯柬帕,Pipfile.lock里記錄了所有包和子依賴包的確切版本哟忍,因此是確定構(gòu)建

$ pipenv install --ignore-pipfile

如果要在另一個開發(fā)環(huán)境做開發(fā),則將代碼和Pipfile復(fù)制過去陷寝,運行以下命令:

$ pipenv install --dev

由于Pipfile里面沒有所有子依賴包或者確定的版本锅很,因此該安裝可能會更新未指定模塊的版本號,這不僅不是問題凤跑,還解決了一些其他問題爆安,我在這里做一下解釋:

假如該命令更新了一些依賴包的版本,由于我肯定還會在新環(huán)境做單元測試或者功能測試仔引,因此我可以確保這些包的版本更新是不會影響軟件功能的扔仓;然后我會pipenv lock并把它發(fā)布到生產(chǎn)環(huán)境,因此我可以確定生產(chǎn)環(huán)境也是不會有問題的咖耘。這樣一來翘簇,我既可以保證生產(chǎn)環(huán)境和開發(fā)環(huán)境的一致性,又可以不用管理眾多依賴包的版本儿倒,完美的解決方案版保!

pipenv依賴分析詳解

pipenv每次安裝核心包時,都會檢測所有核心包的子依賴包义桂,對不滿足的子依賴包會做更新找筝。如果核心包package_a和package_b依賴有矛盾,比如(package_a依賴package_c>2.0, package_b依賴package_c<1.9)慷吊,則會有警告提示。

使用以下命令可以查看依賴關(guān)系:

$ pipenv graph

舉個栗子:

Flask==0.12.1
  - click [required: >=2.0, installed: 6.7]
  - itsdangerous [required: >=0.21, installed: 0.24]
  - Jinja2 [required: >=2.4, installed: 2.10]
    - MarkupSafe [required: >=0.23, installed: 1.0]
  - Werkzeug [required: >=0.7, installed: 0.14.1]
numpy==1.14.1
pytest==3.4.1
  - attrs [required: >=17.2.0, installed: 17.4.0]
  - funcsigs [required: Any, installed: 1.0.2]
  - 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.5,<2.7, installed: 2.6]
  - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]

Pipfile

舉個栗子曹抬,它是 TOML 格式的:

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

[dev-packages]
pytest = "*"

[packages]
flask = "==0.12.1"
numpy = "*"
requests = {git = "https://github.com/requests/requests.git", editable = true}

[requires]
python_version = "3.6"

我不用管子依賴包溉瓶,只會把我項目中實際用到的包放進去,子依賴包在pipenv install package的時候自動安裝或更新。

Pipfile.lock

舉個栗子堰酿,它是JSON格式的疾宏,它包含了所有子依賴包的確定版本:

{
    "_meta": {
        ...
    },
    "default": {
        "flask": {
            "hashes": [
                "sha256:6c3130c8927109a08225993e4e503de4ac4f2678678ae211b33b519c622a7242",
                "sha256:9dce4b6bfbb5b062181d3f7da8f727ff70c1156cbb4024351eafd426deb5fb88"
            ],
            "version": "==0.12.1"
        },
        "requests": {
            "editable": true,
            "git": "https://github.com/requests/requests.git",
            "ref": "4ea09e49f7d518d365e7c6f7ff6ed9ca70d6ec2e"
        },
        "werkzeug": {
            "hashes": [
                "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b",
                "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
            ],
            "version": "==0.14.1"
        }
        ...
    },
    "develop": {
        "pytest": {
            "hashes": [
                "sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d",
                "sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6"
            ],
            "version": "==3.4.1"
        },
        ...
    }
}

我永遠也不應(yīng)該編輯Pipfile.lock, 它只應(yīng)該由pipenv lock生成。

pipenv的其他指令

卸載包

$ pipenv uninstall numpy

當前虛擬環(huán)境目錄

$ pipenv --venv

當前項目根目錄

$ pipenv --where

舊項目的requirments.txt轉(zhuǎn)化為Pipfile

使用pipenv install會自動檢測當前目錄下的requirments.txt, 并生成Pipfile, 我也可以再對生成的Pipfile做修改触创。

此外以下命令也有同樣效果, 可以指定具體文件名:

$ pipenv install -r requirements.txt

如果我有一個開發(fā)環(huán)境的requirent-dev.txt, 可以用以下命令加入到Pipfile:

$ pipenv install -r dev-requirements.txt --dev

是否要將Pipfile加入到版本管理

按照上文分析坎藐,代碼和Pipfile都應(yīng)該加入版本管理,Pipfile.lock就見仁見智了哼绑,我傾向于不加入到版本管理岩馍,因為Pipfile.lock在不同的操作系統(tǒng),不同的開發(fā)階段都可能發(fā)生變化抖韩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛀恩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茂浮,更是在濱河造成了極大的恐慌双谆,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件席揽,死亡現(xiàn)場離奇詭異顽馋,居然都是意外死亡,警方通過查閱死者的電腦和手機幌羞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門趣避,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人新翎,你說我怎么就攤上這事程帕。” “怎么了地啰?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵愁拭,是天一觀的道長。 經(jīng)常有香客問我亏吝,道長岭埠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任蔚鸥,我火速辦了婚禮惜论,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘止喷。我一直安慰自己馆类,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布弹谁。 她就那樣靜靜地躺著乾巧,像睡著了一般句喜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沟于,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天咳胃,我揣著相機與錄音,去河邊找鬼旷太。 笑死展懈,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的供璧。 我是一名探鬼主播存崖,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嗜傅!你這毒婦竟也來了金句?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤吕嘀,失蹤者是張志新(化名)和其女友劉穎违寞,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體偶房,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡趁曼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了棕洋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挡闰。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掰盘,靈堂內(nèi)的尸體忽然破棺而出摄悯,到底是詐尸還是另有隱情,我是刑警寧澤愧捕,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布奢驯,位于F島的核電站,受9級特大地震影響次绘,放射性物質(zhì)發(fā)生泄漏瘪阁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一邮偎、第九天 我趴在偏房一處隱蔽的房頂上張望管跺。 院中可真熱鬧,春花似錦禾进、人聲如沸豁跑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贩绕。三九已至火的,卻和暖如春壶愤,著一層夾襖步出監(jiān)牢的瞬間淑倾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工征椒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娇哆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓勃救,卻偏偏與公主長得像碍讨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蒙秒,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353