Python 依賴管理的迷宮

2022年09月14日11:15:02 科技 1187

在這篇文章中,我想對 Python 中的依賴管理有所了解。Python 依賴管理是一個完全不同的世界。

Python 依賴管理的迷宮 - 天天要聞

20 多年來,我一直在為 JVM 開發代碼,首先是 Java,然後是 Kotlin。但是,JVM 並不是靈丹妙藥,例如,在腳本中:

  1. 虛擬機需要額外的內存
  2. 在許多情況下,腳本運行的時間不夠長,無法在性能方面獲得任何好處。位元組碼被解釋並且永遠不會編譯為本機代碼。

由於這些原因,我現在用 Python 編寫腳本。其中之一從不同來源收集社交媒體指標並將其存儲在 BigQuery 中以供分析。

我不是 Python 開發人員,但我正在學習 - 很難。在這篇文章中,我想對 Python 中的依賴管理有所了解。

Python 中足夠的依賴管理

在 JVM 上,依賴管理似乎是一個已解決的問題。首先,您選擇您的構建工具,最好是 Maven 或另一種我不應該命名的工具。然後,您聲明您的直接依賴關係,並且該工具管理間接依賴關係。這並不意味著沒有陷阱,但您可以或多或少地快速解決它們。

Python 依賴管理是一個完全不同的世界。首先,在 Python 中,運行時及其依賴項是系統範圍的。一個系統只有一個運行時,並且依賴項在該系統上的所有項目之間共享。因為不可行,所以開始一個新項目的第一件事就是創建一個虛擬環境。

這個問題的解決方案是創建一個虛擬環境,一個自包含的目錄樹,其中包含特定版本的 Python 的 Python 安裝,以及一些額外的包。

然後不同的應用程序可以使用不同的虛擬環境。為了解決前面的衝突需求示例,應用程序 A 可以擁有自己的安裝了 1.0 版的虛擬環境,而應用程序 B 擁有另一個安裝了 2.0 版的虛擬環境。如果應用程序 B 需要將庫升級到版本 3.0,這不會影響應用程序 A 的環境。

--虛擬環境和包

一旦完成,事情就會認真開始。

pipPython 提供了一個開箱即用的依賴管理工具:

您可以使用名為 pip 的程序安裝、升級和刪除軟體包。

--使用 pip 管理包

工作流程如下:

  1. 在虛擬環境中安裝所需的依賴項:pip install flask
  2. 在安裝了所有必需的依賴項後,將它們保存在requirements.txt按約定命名的文件中:pip freeze > requirements.txt

    該文件應與常規代碼一起保存在一個人的VCS中。

  3. pip其他項目開發人員可以通過指向安裝相同的依賴項requirements.txt:pip install -r requirements.txt

以下是requirements.txt上述命令的結果:

click==8.1.3
Flask==2.2.2
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
Werkzeug==2.2.2

依賴和傳遞依賴

在描述這個問題之前,我們需要解釋一下什麼是傳遞依賴。傳遞依賴項是項目不直接需要的依賴項,而是項目的依賴項之一或依賴項的依賴項一直需要的依賴項。在上面的示例中,我添加了flask依賴項,但pip總共安裝了 6 個依賴項。

我們可以安裝deptree依賴來檢查依賴樹。

pip install deptree

輸出如下:

Flask==2.2.2 # flask
Werkzeug==2.2.2 # Werkzeug>=2.2.2
MarkupSafe==2.1.1 # MarkupSafe>=2.1.1
Jinja2==3.1.2 # Jinja2>=3.0
MarkupSafe==2.1.1 # MarkupSafe>=2.0
itsdangerous==2.1.2 # itsdangerous>=2.0
click==8.1.3 # click>=8.0

# deptree and pip trees

它的內容如下:Flaskrequires Werkzeug,這反過來又需要MarkupSafe。Werkzeug並MarkupSafe有資格作為我的項目的傳遞依賴項。

版本部分也很有趣。第一部分提到安裝的版本,而注釋部分是指兼容的版本範圍。例如Jinja需要版本3.0或以上,安裝的版本為3.1.2.

安裝的版本是安裝時找到的最新兼容pip版本。pip並deptree了解setup.py沿每個庫分發的文件的兼容性:

安裝腳本是使用 Distutils 構建、分發和安裝模塊的所有活動的中心。設置腳本的主要目的是向 Distutils 描述您的模塊分發,以便對您的模塊進行操作的各種命令執行正確的操作。

--編寫安裝腳本

flask在這裡:

from setuptools import setup

setup(
name="Flask",
install_requires=[
"Werkzeug >= 2.2.2",
"Jinja2 >= 3.0",
"itsdangerous >= 2.0",
"click >= 8.0",
"importlib-metadata >= 3.6.0; python_version < '3.10'",
],
extras_require={
"async": ["asgiref >= 3.2"],
"dotenv": ["python-dotenv"],
},
)

點和傳遞依賴

出現問題是因為我希望我的依賴項是最新的。為此,我已將 Dependabot 配置為監視requirements.txt. 當這樣的事件發生時,它會在我的 repo 中打開一個PR 。大多數時候,PR 就像一個魅力,但在少數情況下,當我在合併後運行腳本時會發生錯誤。它如下所示:

純文本1錯誤:libfoo 1.0.0 要求 libbar<2.5,>=2.0,但您將擁有不兼容的 libbar 2.5。

問題是 Dependabot 為列出的每個庫打開一個 PR。但是可以發布一個新的庫版本,這超出了兼容性的範圍。

想像一下下面的情況。我的項目需要libfoo依賴。反過來,libfoo需要libbar依賴。在安裝時,pip使用最新版本libfoo和最新兼容版本的libbar. 結果requirements.txt是:

純文本1libfoo==1.0.02庫==2.0

一切都按預期工作。過了一會兒,Dependabot 運行並發現libbar已經發布了一個新版本,例如2.5. 忠實地,它打開了一個 PR 來合併以下更改:

純文本1libfoo==1.0.02庫==2.5

是否出現上述問題僅取決於如何libfoo 1.0.0在setup.py. 如果2.5在兼容範圍內,則有效;如果沒有,它不會。

pip-compile拯救

問題pip在於它列出了傳遞依賴和直接依賴。Dependabot 然後獲取所有依賴項的最新版本,但不驗證傳遞依賴項版本更新是否在該範圍內。它可能會檢查,但requirements.txt文件格式不是結構化的:它不區分直接依賴和傳遞依賴。顯而易見的解決方案是僅列出直接依賴項。

好消息是pip只允許列出直接依賴項;它自動安裝傳遞依賴。壞消息是我們現在有兩個requirements.txt選項無法區分它們:一些僅列出直接依賴關係,而另一些則列出所有依賴關係。

它需要一個替代方案。pip-tools有一個:

  1. 一個在一個文件中列出了它們的直接依賴關係,該requirements.in文件的格式與requirements.txt
  2. 該pip-compile工具requirements.txt從requirements.in.

例如,給定我們的 Flask 示例:

#
# This file is autogenerated by pip-compile with python 3.10
# To update, run:
#
# pip-compile requirements.in
#
click==8.1.3
# via flask
flask==2.2.2
# via -r requirements.in
itsdangerous==2.1.2
# via flask
jinja2==3.1.2
# via flask
markupsafe==2.1.1
# via
# jinja2
# werkzeug
werkzeug==2.2.2
# via flask

pip install -r requirements.txt

它具有以下好處和後果:

  • 生成的requirements.txt包含注釋以了解依賴關係樹
  • 由於pip-compile生成文件,您不應將其保存在 VCS 中
  • 該項目與依賴於的遺留工具兼容requirements.txt
  • 最後但同樣重要的是,它改變了安裝工作流程。不是安裝包然後保存它們,而是首先列出包然後安裝它們。

此外,Dependabot 可以管理pip-compile.

結論

這篇文章描述了默認 Python 的依賴管理系統以及它如何破壞自動版本升級。我們繼續描述pip-compile解決問題的替代方案。

請注意,Python 存在依賴管理規範,PEP 621 – 在 pyproject.toml 中存儲項目元數據。它類似於 Maven 的 POM,但格式不同。這在我的腳本上下文中是多餘的,因為我不需要分發項目。但是你應該這樣做,知道它pip-compile是兼容的。


科技分類資訊推薦

長安與東風重組新進展:朱華榮稱不會改變長安既定戰略 - 天天要聞

長安與東風重組新進展:朱華榮稱不會改變長安既定戰略

2月9日,長安汽車和東風集團股份(00489.HK)同步發布了控股股東「正在與其他國資央企集團籌劃重組事項」的信息。長安汽車的控股股東是兵裝集團,而東風集團股份的控股股東是東風公司。隨即,長安汽車和東風集團這兩家汽車央企將合併重組,成為業內關注的焦點。
公安部出手了!年齡限制放寬10年、送考下鄉,2025年考駕照不難了 - 天天要聞

公安部出手了!年齡限制放寬10年、送考下鄉,2025年考駕照不難了

電動車加強管理以後,要求機動車類型的車輛需要持證上路,但是老年人考駕照卻受阻,一方面有年齡的限制,另一方面偏遠山區考駕照不方便,所以在2025年公安部出手了,年齡限制放寬10年,同時推出送考下鄉服務,還進一步的降低考駕照的費用,2025年起考摩托車駕照不難了。
從「星靈安全守護體系」到昊鉑HL,看懂廣汽科技日 - 天天要聞

從「星靈安全守護體系」到昊鉑HL,看懂廣汽科技日

發布會以技術切入,並全程圍繞安全展開。廣汽集團董事長、總經理馮興亞率先登場,宣布2025年四季度將正式上市支持L3級智能駕駛的車型,他同時強調面向自動駕駛時代對智能駕駛技術、整車安全架構以及突發風險處理能力的要求更高。如何才能滿足更高的要求?馮興亞提到了「廣汽
關稅大棒下,最受傷的車企出現了 - 天天要聞

關稅大棒下,最受傷的車企出現了

特朗普的關稅大棒剛揮出,尚未嚇退「外敵」,卻先刺痛了自己。近日,擁有瑪莎拉蒂、Jeep等14個品牌的全球第四大車企斯泰蘭蒂斯突然宣布裁撤900名美國工人,關閉加拿大和墨西哥兩家工廠,北美生產線陷入癱瘓。幾乎同一時間,捷豹路虎宣布暫停對美出口一個月,奧迪更是直接