相依性解析

pip 可用於確定和安裝軟體套件的相依性。確定要安裝哪個版本的相依性的過程稱為相依性解析。可以透過將 --no-deps 傳遞給 pip install 來停用此行為。

如何運作

當使用者執行 pip install(例如:pip install tea),pip 需要找出套件的相依性(例如:spoonhot-watertea-leaves 等)以及它應該要安裝的每個相依性的版本。

pip install 執行的開始,pip 沒有已請求套件的所有相依性資訊。它需要找出已請求套件的相依性、這些相依性的相依性,以此類推。在相依性解析處理進行期間,pip 將需要下載用於取得套件的相依性的套件的發行檔案。

回溯

在 20.3 版中已更改: pip 的相依性解析器現在有回溯功能。

在相依性解析期間,pip 需要假設它需要安裝的套件版本,然後稍後檢查這些假設是否不正確。當 pip 發現它之前做出的假設不正確時,它必須回溯,這表示還要放棄一些已經完成的工作,然後返回選擇另一條路徑。

這看來很像 pip 下載多個版本的同一個套件,因為 pip 明確地向使用者顯示每個下載。在這個步驟中所做的選擇的回溯並非預期之外的行為或錯誤。這是 Python 套件相依性解析的工作方式的一部分。

範例

使用者請求 pip install tea。套件 tea 宣告相依於 hot-waterspooncup 等。

pip 首先選擇 tea 的最新版本,並取得該版本的 tea 相依套件清單。之後會對這些套件重複這個程序,選擇 spoon 的最新版本,然後選擇 cup。接著,pip 發現它所選擇的 cup 版本與它所選擇的 spoon 版本不相容。因此,pip 會「回到」後退),並嘗試使用另一個版本 cup。如果成功,它會繼續進行下一個套件(如 sugar)。否則,它會繼續回溯 cup,直到找到一個與所有其他套件相容的 cup 版本為止。

這看起來就像

$ pip install tea
Collecting tea
  Downloading tea-1.9.8-py2.py3-none-any.whl (346 kB)
     |████████████████████████████████| 346 kB 10.4 MB/s
Collecting spoon==2.27.0
  Downloading spoon-2.27.0-py2.py3-none-any.whl (312 kB)
     |████████████████████████████████| 312 kB 19.2 MB/s
Collecting cup>=1.6.0
  Downloading cup-3.22.0-py2.py3-none-any.whl (397 kB)
     |████████████████████████████████| 397 kB 28.2 MB/s
INFO: pip is looking at multiple versions of this package to determine
which version is compatible with other requirements.
This could take a while.
  Downloading cup-3.21.0-py2.py3-none-any.whl (395 kB)
     |████████████████████████████████| 395 kB 27.0 MB/s
  Downloading cup-3.20.0-py2.py3-none-any.whl (394 kB)
     |████████████████████████████████| 394 kB 24.4 MB/s
  Downloading cup-3.19.1-py2.py3-none-any.whl (394 kB)
     |████████████████████████████████| 394 kB 21.3 MB/s
  Downloading cup-3.19.0-py2.py3-none-any.whl (394 kB)
     |████████████████████████████████| 394 kB 26.2 MB/s
  Downloading cup-3.18.0-py2.py3-none-any.whl (393 kB)
     |████████████████████████████████| 393 kB 22.1 MB/s
  Downloading cup-3.17.0-py2.py3-none-any.whl (382 kB)
     |████████████████████████████████| 382 kB 23.8 MB/s
  Downloading cup-3.16.0-py2.py3-none-any.whl (376 kB)
     |████████████████████████████████| 376 kB 27.5 MB/s
  Downloading cup-3.15.1-py2.py3-none-any.whl (385 kB)
     |████████████████████████████████| 385 kB 30.4 MB/s
INFO: pip is looking at multiple versions of this package to determine
which version is compatible with other requirements.
This could take a while.
  Downloading cup-3.15.0-py2.py3-none-any.whl (378 kB)
     |████████████████████████████████| 378 kB 21.4 MB/s
  Downloading cup-3.14.0-py2.py3-none-any.whl (372 kB)
     |████████████████████████████████| 372 kB 21.1 MB/s

這些多個 Downloading cup-{version} 行列顯示在相依性解析過程中,pip 將回溯它正在進行的選擇。

如果 pip 在相依性解析過程中開始回溯,它不知道會重新考慮多少個選擇以及需要多少計算。

對使用者而言,表示 pip 開始回溯時,完成可能需要很長一段時間。如果一個套件有很多版本,要找出一個好的候選套件可能會花費大量時間。所需的時間取決於套件大小、pip 必須嘗試的版本數以及其他各種因素。

回溯減少安裝新套件意外中斷已安裝套件的風險,因此降低環境發生混亂的風險。為此,pip 必須執行更多工作,才能找出哪個版本的套件是安裝的理想候選套件。

減少回溯的可能方式

對於 pip 在相依性解析過程中過度回溯的情況,並沒有一個適用於所有情況的答案。不過,有些方法可以減少 pip 可能進行回溯的程度。幾乎所有這些方法都需要經過一定程度的嘗試和錯誤。

讓 pip 完成回溯

在大部分情況下,pip 會成功完成回溯程序。這可能需要花費很長的時間才能完成,因此這可能不是你偏好的選項。

然而,pip 仍可能找不到一組相容的版本。針對這點,pip 會嘗試它需要的所有可能組合,並判定沒有任何一組相容。

如果你不想等待,可以中斷 pip(Ctrl+c)並嘗試下列所列策略。

減少 pip 試圖使用的版本數量

通常,可以新增限制條件給 pip 回溯的套件(例如在以上範例中 - cup)。

你可以嘗試類似下列範例

$ python -m pip install tea "cup >= 3.13"
$ python -m pip install tea "cup >= 3.13"
C:> py -m pip install tea "cup >= 3.13"

這會減少 pip 嘗試的 cup 版本數量,並可能縮短 pip 的安裝時間。

新增的限制條件有可能是錯誤的。當這發生時,縮小的搜尋空間讓 pip 能夠更快速地找出衝突原因,並將其呈現給使用者。這也可能導致 pip 由於其他衝突而回溯其他套件。

使用限制條件檔案或鎖定檔

這個選項是前一段的延伸。它需要使用者知道如何檢查

  • 他們試著安裝的套件

  • 套件發佈頻率和相容性政策

  • 他們從舊版本中的發佈說明和變更日誌

在佈署過程中,你可以建立一個鎖定檔,指出那個套件中每個相依套件的明確套件和版本號碼。你可以使用 pip-tools 建立它。

這表示「工作」在開發過程中只會執行一次,因此可以避免在佈署時執行相依項性解析。

處理相依項性衝突

這段提供實作建議給遇到 ResolutionImpossible 錯誤的 pip 使用者,其中 pip 無法安裝它們指定的套件,因為相依項性衝突。

了解你的錯誤訊息

當你收到 ResolutionImpossible 錯誤時,你可能會看到類似以下的訊息

$ python -m pip install package_coffee==0.44.1 package_tea==4.3.0
[regular pip output]
ERROR: Cannot install package_coffee==0.44.1 and package_tea==4.3.0 because these package versions have conflicting dependencies.

The conflict is caused by:
    package_coffee 0.44.1 depends on package_water<3.0.0,>=2.4.2
    package_tea 4.3.0 depends on package_water==2.3.1
$ python -m pip install package_coffee==0.44.1 package_tea==4.3.0
[regular pip output]
ERROR: Cannot install package_coffee==0.44.1 and package_tea==4.3.0 because these package versions have conflicting dependencies.

The conflict is caused by:
    package_coffee 0.44.1 depends on package_water<3.0.0,>=2.4.2
    package_tea 4.3.0 depends on package_water==2.3.1
C:> py -m pip install package_coffee==0.44.1 package_tea==4.3.0
[regular pip output]
ERROR: Cannot install package_coffee==0.44.1 and package_tea==4.3.0 because these package versions have conflicting dependencies.

The conflict is caused by:
    package_coffee 0.44.1 depends on package_water<3.0.0,>=2.4.2
    package_tea 4.3.0 depends on package_water==2.3.1

在此範例中,pip 無法安裝你要求的套件,因為它們各自相依於同一個套件(package_water)的不同版本

  • package_coffee 版本 0.44.1 相依於小於 3.0.0 但大於或等於 2.4.2package_water 版本

  • package_tea4.3.0 版依賴 package_water2.3.1

有時這些訊息易於閱讀,因為它們使用常見的比較運算子來指定必要的版本(例如 <>)。

不過,Python 封裝也支援一些比較複雜的方法來指定套件版本(例如 ~=*

運算子

描述

範例

>

大於指定版本的任何版本。

>3.1:大於 3.1 的任何版本。

<

小於指定版本的任何版本。

<3.1:小於 3.1 的任何版本。

<=

小於或等於指定版本的任何版本。

<=3.1:小於或等於 3.1 的任何版本。

>=

大於或等於指定版本的任何版本。

>=3.1:大於或等於 3.1 的任何版本。

==

等於指定版本的任何版本。

==3.1:僅版本 3.1

!=

不等於指定版本的任何版本。

!=3.1:除了 3.1 以外的任何版本。

~=

任何相容1版本。

~=3.1:任何與 3.1 相容1 的版本。

*

可以在版本號碼的結尾使用,代表所有

==3.1.*:任何以 3.1 開頭的版本。

1 相容版本是僅在最後一段不同的更高版本。 ~=3.1.2 等同於 >=3.1.2, ==3.1.*~=3.1 等同於 >=3.1, ==3.*

有關支援的比對運算子的詳細說明,請參閱 PEP 440

可能的解決方案

發生錯誤的解決方案取決於各自的用例。以下提供一些可嘗試的方法

稽核頂層需求

稽核專案並移除任何不必要或過期的需求(例如從 setup.pyrequirements.txt),做為第一步。移除這些內容可大幅降低相依性樹的複雜度,從而減少衝突發生的機會。

放寬頂層需求

有時您要求 pip 安裝的套件會不相容,因為您在指定套件版本時過於嚴格。

在我們的首個範例中,package_coffeepackage_tea 已被 固定 使用特定版本(package_coffee==0.44.1 package_tea==4.3.0)。

要找出 package_coffeepackage_tea 依賴相同版本的 package_water 的版本,您可以考慮

  • 放寬您準備安裝的套件範圍(例如 pip install "package_coffee>0.44.*" "package_tea>4.0.0"

  • 要求 pip 安裝 任何 版本的 package_coffeepackage_tea,方法是完全移除版本指定符(例如 pip install package_coffee package_tea

在第二個案例中,pip 會自動找出 package_coffeepackage_tea 依賴相同版本的 package_water 的版本,安裝

  • package_coffee 0.44.1,它依賴 package_water 2.6.1

  • package_tea 4.4.3依賴 package_water 2.6.1

如果您希望優先考慮其中某個套件,您可以為較重要的套件新增版本規格

$ python -m pip install package_coffee==0.44.1 package_tea
$ python -m pip install package_coffee==0.44.1 package_tea
C:> py -m pip install package_coffee==0.44.1 package_tea

這將導致

  • package_coffee 0.44.1,它依賴 package_water 2.6.1

  • package_tea 4.4.3依賴 package_water 2.6.1

現在您已解決問題,可以視需要重新固定相容的套件版本。

放寬您依賴項的要求

假設您無法透過放寬您需要的套件版本 (如前述) 來解決衝突,您可以嘗試透過以下方式來修正您依賴項上的問題:

  • 請求套件維護者放寬依賴項

  • 自行分叉套件,同時放寬依賴項

警告

如果您選擇自行分叉套件,您將不再能獲得套件維護者提供的任何支援。請自行承擔風險!

所有需求皆適當,但找不到解決方案

有時確實找不到不會造成衝突的套件版本組合。歡迎進入 依賴性地獄

在這種情況下,您可以考慮

  • 使用替代套件,如果您的專案可以接受。請參閱 Python 的類似套件

  • 重構您的專案以減少依賴項的數量 (例如,將單一程式碼庫分拆為較小的區塊)。

尋求協助

如果上述建議對您沒有幫助,我們建議您在以下地方尋求協助

請參閱 “如何提出好的問題?” 以瞭解尋求協助的訣竅。

很遺憾,pip 團隊無法對個別依賴項衝突錯誤提供支援。如果您相信自己的問題揭露了 pip 中的錯誤,請pip 的問題追蹤器 上開啟票證。