標籤:

使用pipenv管理你的項目

前言

昨天給pipenv順手提的一個改bug的PR被合併了。無聊之下翻了下貢獻者列表,貌似沒有一個我國的開發者!我的普及工作任重而道遠啊,然後就寫了這篇文章給大家介紹下這個終極大殺器吧。

Python開發者應該聽過pip、easy_install和virtualenv,如果看過我的書應該還知道 virtualenvwrapper、virtualenv-burrito和autoenv,再加上pyvenv、venv(Python 3標準庫)、pyenv...

額,是不是有種發懵的感覺?

那麼現在有個好消息,你可以只使用終極方案: pipenv + autoenv(可選)。

「終極方案」,聽起來好噱頭呀。給出我的理由之前我們先了解一下Python虛擬環境和包管理的歷史吧。

歷史

在Python發展史上出現了很多創建和發布包的工具。 當你想要把你的項目分享出去,放到PYPI或者其他託管服務上的時候,就需要藉助這樣的工具來構建和分發項目。早在1998年Python標準庫內置了模塊distutils,但是只提供了有限的支持,之後社區選擇通過setuptools這個包實現構建和發布,它自帶easy_install,能幫助你找到、下載、安裝以及更新需要使用的包。不過依然功能很有限,比如不能刪除包。

當你做一個專職的Python開發,獨立的虛擬環境也是一個開發中迫切需要的功能,在這裡請大家記住一個 Ian Bicking(下稱ianb) 的開發者,08年,他開發了virtualenv。

社區一些Python核心開發者和知名項目(如Django)核心開發者也在支持和推動這件事,後來成立了pypa(Python Packaging Authority),pypa早期做的就是pip - 現在最主流的安裝包的工具。再提一下,ianb也是pip的早期核心開發者。

不過非常遺憾,由於和社區產生了一些矛盾,ianb很早之前就不再寫Python項目(可見這矛盾多大呀 ??),virtualenv也轉給了其他開發者,這是Python社區一個極大的損失。

現在pip和virtualenv已經被大家所熟知,甚至可以說是Python官方的包管理和虛擬環境選擇。不過其實還是有問題,我舉幾個例子:

  1. 必須手動安裝或刪除某些特定版本的包,並記得定期更新requirements.txt文件,以保持項目環境的一致
  2. 有時項目中需要有多個requirements.txt文件,比如開發時應該用dev-requirements.txt,現有的模式不能滿足這些複雜的需要
  3. 卸載包的時候只是卸載包自己,不能處理相關依賴,時間久了項目環境就混亂了

pipenv 是什麼?

Pipenv 是 Python 項目的依賴管理器。其實它不是什麼先進的理念和技術,如果你熟悉 Node.js 的 npm/yarn 或 Ruby 的 bundler,那麼就非常好理解了,它在思路上與這些工具類似。儘管pip可以安裝Python包,但仍推薦使用Pipenv,因為它是一種更高級的工具,可簡化依賴關係管理的常見使用情況。

主要特性包含:

  1. 根據 Pipfile 自動尋找項目根目錄。
  2. 如果不存在,可以自動生成 Pipfile 和 Pipfile.lock。
  3. 自動在項目目錄的 .venv 目錄創建虛擬環境。(當然這個目錄地址通過設置WORKON_HOME改變)
  4. 自動管理 Pipfile 新安裝和刪除的包。
  5. 自動更新 pip。

對於新手和老手來說都是更好的選擇。

pipenv 都包含什麼?

pipenv 是 Pipfile 主要倡導者、requests 作者 Kenneth Reitz 寫的一個命令行工具,主要包含了Pipfile、pip、click、requests和virtualenv。Pipfile和pipenv本來都是Kenneth Reitz的個人項目,後來貢獻給了pypa組織。Pipfile是社區擬定的依賴管理文件,用於替代過於簡陋的 requirements.txt 文件。

Pipfile的基本理念是:

  1. Pipfile 文件是 TOML 格式而不是 requirements.txt 這樣的純文本。
  2. 一個項目對應一個 Pipfile,支持開發環境與正式環境區分。默認提供 default 和 development 區分。
  3. 提供版本鎖支持,存為 Pipfile.lock。

click是Flask作者 Armin Ronacher 寫的命令行庫,現在Flask已經集成了它。

接下來,我們看看怎麼使用它吧

入門

pipenv兼容Python 2/3,我們這裡以Mac下Python 3為例:

安裝pipenv

? brew install python3 # 如果已經安裝了可以忽略n? python3 -m pip install --upgrade --force-reinstall pipn? pip3 install pipenv --user # 推薦安裝在個人目錄下n? export PATH="/Users/dongweiming/Library/Python/3.6/bin:$PATH" # 把用戶目錄下bin放在最前面,這樣可以直接使用pipenv了n

使用pipenv

用一個空目錄體驗一下:

? mkdir test_pipenvn? cd test_pipenvn? pipenv install # 創建一個虛擬環境nCreating a virtualenv for this project…n...nInstalling setuptools, pip, wheel...done.nVirtualenv location: /Users/dongweiming/.virtualenvs/test_pipenv-GP_s2TW5nCreating a Pipfile for this project…nPipfile.lock not found, creating…nLocking [dev-packages] dependencies…nLocking [packages] dependencies…nUpdated Pipfile.lock (c23e27)!nInstalling dependencies from Pipfile.lock (c23e27)…n ?? ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:00:00nTo activate this projects virtualenv, run the following:n $ pipenv shelln? which python3n/usr/local/Cellar/python3/3.6.1/bin/python3 # 還是mac自帶的Pythonn? pipenv shell # 激活虛擬環境nSpawning environment shell (/bin/zsh). Use exit to leave.nsource /Users/dongweiming/.virtualenvs/test_pipenv-GP_s2TW5/bin/activaten? which python3 # 已經在虛擬環境里了n/Users/dongweiming/.virtualenvs/test_pipenv-GP_s2TW5/bin/python3n? exit # 退出虛擬環境n? which python3n/usr/local/Cellar/python3/3.6.1/bin/python3n

以上就是原來virtualenv的基本用法了。我們看一下當前目錄現在是什麼樣子的:

? lsnPipfile Pipfile.lockn

這個環境下目前什麼都沒有。我們安裝2個包:

? pipenv install elasticsearch-dsl requestsnInstalling elasticsearch-dsl…n...nAdding elasticsearch-dsl to Pipfiles [packages]…nInstalling requests…n...nAdding requests to Pipfiles [packages]…n PS: You have excellent taste! ? ?? ?nLocking [dev-packages] dependencies…nLocking [packages] dependencies…nUpdated Pipfile.lock (8d307d)! n

現在Pipfile.lock已經更新了,包含了 elasticsearch-dsl、requests 和相關依賴的包信息。

另外如果你添加--two或--three標誌到上面的最後一個命令,它分別使用Python 2或3來初始化你的項目。 否則將使用默認版本的Python。

可以看一下依賴關係:

? pipenv graphnelasticsearch-dsl==6.1.0n - elasticsearch [required: <7.0.0,>=6.0.0, installed: 6.1.1]n - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]n - ipaddress [required: Any, installed: 1.0.19]n - python-dateutil [required: Any, installed: 2.6.1]n - six [required: >=1.5, installed: 1.10.0]n - six [required: Any, installed: 1.10.0]nrequests==2.18.4n - certifi [required: >=2017.4.17, installed: 2017.11.5]n - chardet [required: <3.1.0,>=3.0.2, installed: 3.0.4]n - idna [required: <2.7,>=2.5, installed: 2.6]n - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]n

可以看到,他倆都依賴了urllib3。雖然現在pipenv不能直接卸載包及其依賴,但是由於它提供了良好的介面,我們還是可以實現:

? pipenv uninstall `pipenv graph --json |python3 depends.py requests`nUn-installing certifi…nUninstalling certifi-2017.11.5:n Successfully uninstalled certifi-2017.11.5nNo package certifi to remove from Pipfile.nUn-installing requests…nUninstalling requests-2.18.4:n Successfully uninstalled requests-2.18.4nRemoving requests from Pipfile…nUn-installing idna…nUninstalling idna-2.6:n Successfully uninstalled idna-2.6nNo package idna to remove from Pipfile.nUn-installing chardet…nUninstalling chardet-3.0.4:n Successfully uninstalled chardet-3.0.4nNo package chardet to remove from Pipfile.nLocking [dev-packages] dependencies…nLocking [packages] dependencies…nUpdated Pipfile.lock (c05ac4)! n

其中depends.py腳本會解析依賴關係,排除其他包依賴的項目然後刪除:

? cat depends.pynimport sysnimport jsonnpackage = sys.argv[1]nother_dependencies = set()nremoving_dependencies = set([package])nfor i in json.load(sys.stdin):n for p in i[dependencies]:n key = p[key]n if i[package][key] == package:n removing_dependencies.add(key)n else:n other_dependencies.add(key)nprint( .join(removing_dependencies - other_dependencies))n

再看一下現在環境中的包依賴關係:

? pipenv graphnelasticsearch-dsl==6.1.0n - elasticsearch [required: >=6.0.0,<7.0.0, installed: 6.1.1]n - urllib3 [required: >=1.21.1,<1.23, installed: 1.22]n - ipaddress [required: Any, installed: 1.0.19]n - python-dateutil [required: Any, installed: 2.6.1]n - six [required: >=1.5, installed: 1.10.0]n - six [required: Any, installed: 1.10.0]n

是不是很乾凈呢?

其他功能

除了上述基本功能以外,pipenv還有很多附加的功能,我舉幾個日常比較常用的例子:

? pipenv run which python # 「pipenv run」可以激活虛擬環境,並使用shell命令n/Users/dongweiming/.virtualenvs/test_pipenv-GP_s2TW5/bin/pythonn? pipenv check # 檢查裝的包的安全性nChecking PEP 508 requirements…nPassed!nChecking installed package safety…nAll good!n? pipenv --man # 傳統的看文檔的方法n? pipenv check --style depends.py # 代碼Flake8檢查,在這裡我修改了depends.py讓它故意有問題n/Users/dongweiming/test_pipenv/depends.py:1:1: F401 os imported but unused n

另外由於autoenv也是Kenneth Reitz寫的,所以pipenv默認也包含了對.env文件的支持。

是不是方便很多呢?

請關注我的微信公眾號「Python之美」(微信號:python_cn)


推薦閱讀:

列表生成式版圖片拼接——知乎是喵多還是汪多系列
C/C++ 這類更底層的語言,如果把平時常用的高級函數和功能都實現,能否達到 Python 的開發效率?
千里挑一的我乎妹子大V排行榜(數據初探1)
Mixin是什麼概念?

TAG:Python |