命令列介面

pip._internal.cli 套件負責處理及提供 pip 的命令列介面。此套件處理下列項目:

  • 命令列選項定義及剖析

  • 自動完成

  • 分派到各個命令

  • 進度條和 spinner 等公用程式

附註

此文件區段目前仍在編寫中。歡迎對 pip 有興趣的開發人員協助我們完成此文件的編寫。如果您有興趣協助,請在 追蹤問題 中告知我們。

概觀

採用 ConfigOptionParser 實例作為「主要剖析程式」,用於剖析頂層 arg。

接著,Command 使用另一個 ConfigOptionParser 實例,用於剖析特定命令的 arg。

命令結構

此區段顯示各個命令類別繼承的類別樹狀結構。

base_command.py 定義基本 Command 類別,其他各個命令將直接或間接繼承此類別(請參閱此區段結尾處的「命令樹狀結構」)。

此類別使用 ConfigOptionParser(請參閱 組態與命令列介面「混合」),新增一般選項和實例化 cmd_opts 群組,如果每個命令類別需要其他特定選項,則會將此選項新增到該群組中。對於定義特定選項的命令,例如 pip install 命令中的 --dry-run,必須將這些選項新增至 cmd_opts 中(這是 add_options 方法的工作,此方法會在 Command 初始化時自動呼叫)。

基本 Command 具有以下方法:

class Command
main()

類別的主要方法,此方法必定會被呼叫(如 main.py 的 main 所示)。負責呼叫類別的特定 run 方法,並處理可能發生的錯誤。

run()

定義指令實際動作的抽象方法。

add_options()

在類別中插入額外選項的選用方法,在Command初始化時呼叫。

有些指令有更專門的行為,例如pip index。此外,這些指令會繼承自IndexGroupCommand,後者則是繼承自CommandSessionCommandMixin,以建立對應要求的 pip 工作階段。

最後,RequirementCommand繼承自IndexGroupCommand,是那些使用任何形式需求的指令的基礎類別,例如pip install

除了上述類別之外,必須提到最後一個混合類別,CommandSessionCommandMixin即從中繼承:CommandContextMixIn,負責指令的內容。

在下列指令樹中,我們可以看到為不同的 pip 指令定義的階層,其中每個指令都定義在它所繼承的基礎類別下方

指令
├─ cache, check, completion, configuration, debug, freeze, hash, help, inspect, show, search, uninstall
└─ IndexGroupCommand
├─ index, list
└─ RequirementCommand
└─ wheel, download, install

選項定義

cmdoptions.py 模組中定義了一組共用選項,以及當我們呼叫指令的說明,或呼叫 pip index 的說明訊息時,我們看到的 一般選項套件索引選項 群組選項。所有選項都定義為在呼叫後傳回 optparse.Option 執行個體的函式,而特定的選項群組(如 pip config設定檔選項 )則定義在每個特定的指令檔案中(例如參閱 configuration.py)。

引數解析

應用程式的主要進入點定義在 main.py 模組的 main 函式中。此函式負責 自動完成,呼叫 parse_command 函式,並透過會呼叫 main 方法的 create_command 建立和執行子程式。

main_parser.py 模組中定義了 parse_command,它定義了以下兩個函式

parse_command()

負責 pip 程式初步解析的函式。建立主解析程式(參閱下一個函式 create_main_parser)以擷取一般選項和其餘引數。例如,執行 pip --timeout=5 install --user INITools 會將 ['--timeout=5'] 分割成一般選項,而 ['install', '--user', 'INITools'] 則分割成其餘部分。

在此步驟,程式會處理選項 --python--versionpippip help。如果找不到前述任何選項,程式會嘗試擷取指令名稱和引數。

create_main_parser()

建立主解析器 ( 在主控台中輸入指令 pip 可以看到說明)。內部解析器 (ConfigOptionParser) 會在此時新增一般選項群組以及命令清單 (來自 cmdoptions.py)。

在初步的解析完成後,create_command 會負責使用儲存在 commands_dict 變數中的資訊來建立適當的命令,並呼叫其 main 方法 (請參閱 命令結構)。

第二次參數解析則是在每一個特定命令中進行 (定義在基礎 Command 類別中),同樣會使用 ConfigOptionParser

參數存取

要存取所有的選項和參數,Command.run() 會將選項作為 optparse.Values 和參數字串清單 (在 Command.main() 中分析) 來接收。基礎 Command 類別的內部方法負責在針對特定命令呼叫 parse_args 後傳遞這些變數。

組態和 CLI 的「混合」

基礎 Command 會初始化類別 ConfigOptionParser,其負責解析程序 (經由其父類別 optparse.OptionParser)。其主要新增功能包含下列函式

class ConfigOptionParser(OptionParser)
get_default_values()

覆寫原始方法,以允許在選項解析器初始化之後更新預設值。

它可以覆寫預設選項和引數,使用 Configuration 類別(可在 組態 中找到更詳細的說明)來納入環境變數和組態檔案中的設定。

進度條和旋轉條

cli 子套件中還有兩個模組負責顯示程式狀態。

  • progress_bars.py

    此模組包含以下函式

    get_download_progress_renderer()

    它使用 rich 功能來呈現下載進度。

    此函式(用於 download.py 中的 Downloader 類別)可讓使用者在執行 龐大 套件上的 pip install 時觀看下載流程。

  • spinner.py

    此模組的主要函式是

    open_spinner()

    它會產生適當類型的旋轉條,這用於 subprocess.py 模組中的 call_subprocess 函式,讓使用者可以看到有一個程式正在執行中。

  • 待辦事項: 怪癖 / 標準實務 / 廣泛的想法。(避免在選項定義中置入清單、特殊情況下的選項值類型、 )

未來的重構點子

  • 將選項定義變更為更具有宣告性、一致性和靜態資料結構的樣貌,取代目前的 partial(Option, ...) 形式

  • 將進度條和旋轉條移到 cli.ui 子套件中

  • 將所有 Command 類別移到 cli.commands 子套件中(包括基礎類別)