Python 官方團隊在打包項目中踩過的坑

花下貓語:這是 packaging 系列的第三篇譯文,該系列是全網關於此話題的最詳盡(水平也很高)的一個系列。原做者是 Python 官方打包團隊成員,是 virtualenv 和 tox 項目的維護者,及 setuptools 和 pip 項目的貢獻者。前端


英文 | Python packaging - Growing Pains【1】python

原做 | BERNAT GABORgit

譯者 | 豌豆花下貓github

聲明 :本文得到原做者受權翻譯,轉載請保留原文出處,請勿用於商業或非法用途。bootstrap


在前兩篇文章中,我介紹了Python 具備的包類型以及包的構建方式,尤爲介紹了 PEP-517/518。儘管這些更改主要是爲了使打包變得更健壯,可是在實施和發佈時,咱們卻遇到了一些問題。這篇文章將介紹一部分,但願能夠爲你們提供經驗教訓,並提出一些有趣的問題以待未來解決。segmentfault

查看 PEP-517 和 PEP-518 的改動,能夠認爲構建後端(亦即 setuptools、flit)幾乎沒有作什麼,只是經過 Python 模塊提供了功能接口。大部分繁重的工做都在構建前端上,它須要生成隔離的 Python,而後以新的方式調用構建後端。現在當咱們談論構建前端時,咱們的選項主要是 pip 或 poetry(和開發者的 tox)。後端

這些項目由社區維護,由少數活躍的開發者在空閒時間維護。他們並無所以得到報酬,並且須要謹慎考慮這些工具被使用的多種方式。考慮到這一點,在 PEP 被接受以後,還花了幾乎兩年時間才首次實施就不足爲奇了。計劃、測試和實施已經在背後進行了一年多。緩存

可是,儘管作了全部準備工做,不可避免的是,初版確實破壞了一些軟件包,在大多數狀況下,人們作的某些操做使維護人員感到驚訝。讓咱們試着瞭解其中一些例子,以及它們是如何被解決的。 app

Mink Mingle攝/Unsplash--準備好出發!函數

PEP-518

此 PEP 引入了TOML文件格式。 【2】一種專門爲了易於讀/寫配置而建立的格式。儘管在build-system部分下介紹了打包配置,但其它工具能夠自由地將其配置放在tool:name部分下,由於它們擁有 PyPi 命名空間中的名字。各類工具當即開始利用這一點(例如Towncrier【3】、 black【4】等)。

pip 18.0(於2018年7月22日發佈) 【5】添加對 PEP-518 包的支持時,使用 pyproject.toml 最先出問題,由於 PEP-518 要求全部帶 pyproject.toml 的軟件包必須指定 build-backend 部分。可是,軟件包事先僅將其用於其它項目的配置文件,因爲它們沒有事先指定它,當 pip 碰到這些文件時,就會引起錯誤,提示 pyproject.toml 文件無效。

PEP-517

pip wheel 緩存問題

pip 在 PEP-517 世界中的安裝方式是首先生成一個 wheel,而後將其提取。要進入 PEP-517 世界,必須指定 build-backend 鍵,不然每條聲明都須要退回到使用 setup.py 命令。

當 pip 構建 wheel 時,默認狀況下會經過緩存系統完成。這是一種提速機制,爲了在多個虛擬環境須要同一個 wheel 時,咱們不用對其進行重建,而是重複使用它。PEP-517 wheel 的構建操做也利用了這一機制。

可是,當你禁用緩存時,這就變得很麻煩。由於沒有目標文件夾可用於構建 wheel。因此構建過程將失敗,請參閱附錄的問題。【6】這個問題雖然很早就顯現出來了,但因爲大多數 CI 系統都在啓用該選項的狀況下運行。僅在一天後,pip 19.0.1 修復了該問題。

pyproject.toml 沒有加入 setuptools 中

事實證實,構建後端實際上要作的工做不只僅是 PEP-517 中描述的公開其 API。後端還須要確保 pyproject.toml 被附加到已構建的源碼包中,不然用戶計算機上的構建後端將沒法使用它。setuptools 1650【7】將爲setuptools【8】修復此問題,在早期版本中,只需在 MANIFEST.in 中指定 pyproject.toml 便可。

Jorge Zapata攝/Unsplash--什麼?!那永遠不會發生

從 setup.py 中導入構建的包

另外一個意外問題是從 setup.py 內導入軟件包時。按照約定,軟件包的版本既做爲軟件包的元數據公開(setup.py 中的 setuptools,setup 函數的 version 參數),也在軟件包根目錄的__version__ 變量公開。能夠在兩個地方都指定變量的內容,可是要使其保持同步就很麻煩。

一種解決方法:許多程序包將其放在根目錄的 version.py 中,而後同時從 setup.py 和程序包根目錄導入它,像這樣from mypy.version import __version__ as version。這能起做用,由於當有人調用 Python 腳本時,當前的工做目錄會自動被添加到 sys.path 中(所以你能夠導入公開在其下的內容)。

可是,這種添加當前工做目錄的行爲歷來不是強制的,更多的是經過python setup.py sdist 調用構建時,產生的反作用。因爲這種行爲是反作用(並不是保證),所以從 setup.py 導入的全部項目都應在構建開始時,將腳本文件夾顯式地添加到 sys 路徑。

是否該在打包期間(當還沒有構建/分發時)導入已編譯的軟件包,這尚有爭議(儘管 Python 打包組傾向於這樣作)。然而,實際上當 setuptools 經過 setuptools.build_meta 暴露其接口時,它選擇不把當前工做目錄添加到系統路徑。

PEP 從未要求後端作此添加,由於大多數構建後端(本質上是聲明式的)根本不須要它。所以,此類功能被認爲是前端的責任。setuptools 認爲,若是用戶須要此功能,則應在 setup.py 中明確指出,並提早手動在 sys.path 中添加相應的路徑。

爲了簡化 pip 代碼庫,pip 決定加入 PEP-517,讓全部人在 setuptools 後端加上 pyproject.toml。如今由於這個問題,即便沒有選擇加入 PEP-517 的程序包也出現崩潰。爲了解決這個問題,setuptools 添加了一個新的構建後端(setuptools.build_meta:__ legacy__),當未指定構建後端時,前端可將其用做默認值;當項目添加 build-backend 鍵時,它們還必須更改其 setup.py,要麼將源碼根目錄添加到 sys.path,要麼避免從源碼根目錄導入。

自舉的後端

還出現了另外一個有趣的問題,該問題的用戶羣更加緊密,可是卻暴露了一個有趣的問題。若是咱們不想使用 wheel,咱們只能經過源發行版進行設置;咱們應該如何解決」如何提供構建後端的構建後端的問題「?例如,setuptools 經過setuptools 打包自身。也即當 setuptools 經過 PEP-517 指定了這一點時,構建前端將被放入無限循環內。

要安裝 pugs 庫,它首先會嘗試建立一個隔離的環境。這個環境須要 setuptools ,所以構建前端就須要構建一個 wheel 來知足它。wheel 構建自己將觸發隔離環境的建立,該環境又依賴於 setuptools。

如何打破這個循環?要求全部構建後端必須暴露爲 wheel?容許後端構建自身?這些自建後端是否應該負擔依賴項?漫長的各類觀點間爭論,利與弊,因此若是你有興趣,請進入python Discourse board【9】,發表你的意見。

Sneaky Elbow攝/Unsplash--咱們是一夥的

小結

打包是很難的。在業餘時間完善打包系統,使用戶能夠在打包期間編寫和運行任意代碼,但還不引發任何破壞,這幾乎是不可能的。

如今有了 PEP-518,構建時依賴項是明確的,而且構建環境易於建立。有了 PEP-517,咱們可使用更具聲明性的打包命名空間,這減小了用戶犯錯的可能,當錯誤不可避免時,也能提供更好的消息。

誠然,在進行這些更改時,某些程序包可能會損壞,而且咱們可能令曾經有效的方法失效。可是,咱們(PyPa 的維護者)並非出於惡意而這樣作的,所以,當出現錯誤時,請務必填寫詳細的錯誤報告,例如什麼錯誤、你的使用方法,以及你的用例。

咱們努力在真誠地改善打包生態系統,爲此咱們建立了集成測試【10】存儲庫,以確保未來至少能夠捕獲到其中的一些邊緣用例,省得它們落入到你的機器中。若是你對打包有任何建議或訴求,請隨時在「 討論Python論壇【11】」的打包部分進行討論,或者爲相關工具提一個 issue。

Milan Popovic攝/ Unsplash--結束了

先到此爲止了,謝謝閱讀完!我要感謝Paul Ganssle【12】審閱了打包系列文章,並要感謝Tech At Bloomberg【13】容許我在工做期間做開源貢獻。

### 相關連接

[1] Python packaging - Growing Pains: https://www.bernat.tech/growi...

[2] TOML文件格式。: https://github.com/toml-lang/...

[3] Towncrier: https://pypi.org/project/town...

[4] black: https://pypi.org/project/black/

[5] pip 18.0(於2018年7月22日發佈): https://pip.pypa.io/en/stable...

[6] 請參閱附錄的問題。: https://github.com/pypa/pip/i...

[7] setuptools 1650: https://github.com/pypa/setup...

[8] setuptools: https://github.com/pypa/setup...

[9] python Discourse board: https://discuss.python.org/t/...

[10] 集成測試: https://github.com/pypa/integ...

[11] 討論Python論壇: https://discuss.python.org/c/...

[12] Paul Ganssle: https://twitter.com/pganssle

[13] Tech At Bloomberg: https://twitter.com/techatblo...

公衆號【Python貓】, 本號連載優質的系列文章,有喵星哲學貓系列、Python進階系列、好書推薦系列、技術寫做、優質英文推薦與翻譯等等,歡迎關注哦。

相關文章
相關標籤/搜索