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是兼容的。


科技分類資訊推薦

全球發明大會中國區上海開賽,超2000名學生參賽,宇樹機器人也穿上賽服 - 天天要聞

全球發明大會中國區上海開賽,超2000名學生參賽,宇樹機器人也穿上賽服

7月4日,2024-2025年度全球發明大會中國區(ICC)上海賽區在寶山區青少年活動中心開賽。宇樹科技機器人G1與2000多名來自長三角等地區的參賽青少年一樣,也穿上賽服躍躍欲試。它還和小發明家一起,與現場觀賽的中國科學院院士、上海技術物理研究所研究員、世界電磁波科學界最高獎得主沈學礎等握手相擁。沈學礎院士與小選手在...
朝陽前瞻布局元宇宙,未來顯示產業園等成果批量上新 - 天天要聞

朝陽前瞻布局元宇宙,未來顯示產業園等成果批量上新

元宇宙是北京市重點布局的未來產業之一。7月4日,作為全國規模最大、產業鏈生態最完整的元宇宙(互聯網3.0)生態發展集聚區,朝陽區舉辦2025全球數字經濟大會AIGC與元宇宙融合發展論壇。AIGC(人工智慧內容生成)工具平台、2025朝陽區元宇宙標杆示範應用場景、元宇宙應用場景示範基地、未來顯示產業園、ULive超現場播控中心...
虛假信息面前,AI為何「智商下線」? - 天天要聞

虛假信息面前,AI為何「智商下線」?

□曹欣怡(雲南財經大學)7月4日,「DeepSeek給王一博道歉是假的」衝上微博熱搜。據稱,這家人工智慧公司因內容審核疏漏,將王一博與「李愛慶腐敗案」不當關聯,損害了其名譽,並已作出正式道歉。
無3C標識充電寶「禁飛」首周:民航與鐵路安檢標準不一 - 天天要聞

無3C標識充電寶「禁飛」首周:民航與鐵路安檢標準不一

自6月28日起,民航局禁止旅客攜帶無3C標識及被召回的充電寶乘坐境內航班,另一方面,鐵路部門並不查驗充電寶3C認證標識或品牌。針對充電寶「禁飛」一周來的落實情況,記者進行了走訪調查。濟南遙牆國際機場:鼓包或破損的充電寶也「禁飛」7月4日,濟南遙牆國際機場工作人員向記者表示,該機場嚴格執行民航局通知,禁止旅客...
最新!白雲機場:充電寶7天內免費暫存 - 天天要聞

最新!白雲機場:充電寶7天內免費暫存

今天(7月4日)是民航局充電寶乘機攜帶新政策正式實施的第6天,記者從廣州白雲機場獲悉,旅客攜帶不合規充電寶的數量呈明顯減少趨勢。據悉,白雲機場提供充電寶暫存服務供旅客選擇,兩座航站樓均設有暫存點,7天內免費暫存,7天後視為自棄處理。根據民航局通知要求,為切實保障航空運行安全,6月28日起禁止旅客攜帶沒有3C標...
小鵬G7正式上市 極致AI科技與滿配舒適兼得 - 天天要聞

小鵬G7正式上市 極致AI科技與滿配舒適兼得

日前,小鵬汽車正式發布全新AI智能家庭SUV——小鵬G7。新車共推出602長續航Max、702超長續航Max、702超長續航Ultra三個版本,上市即刻可以交付。 作為全球首款L3級算力的AI汽車,小鵬G7不僅實現了2250TOPS有效算力以及本地端VLA+VLM大模型的行業首發,更以行業領先的「追光全景」抬頭顯示、「857」的領先三電配置、太極AI底...