Python Distutils-SIG: 設計提案
Python Distutils-SIG
(先決條件:在嘗試閱讀此設計文件之前,請先閱讀提議的介面;它很大程度上是介面文件的續篇。)
設計提案
Distutils 的觀點
setup.py 只需匯入一個模組,即 distutils.core
。此模組負責解析 setup.py 的所有命令列引數(儘管選項的解釋分佈在各種 Distutils 命令中,並且可能分佈在客戶端 setup.py 中)。它還負責接收來自 setup.py 的控制,並將其適當地傳遞給 Distutils 命令。最重要的是,distutils.core
定義了 Distribution
類,它是 Distutils 的核心。客戶端 (setup.py) 主要用於為 Distribution
例項提供屬性,所有 Distutils 命令都操作該例項。distutils.core
還定義了 Command
類,這對於實現 Distutils 命令非常有用。
說到 Distutils 命令:每個命令都作為 Python 模組實現,例如 build
命令由 distutils.build
模組實現。每個命令模組都需要定義一個類,該類也以命令命名——例如 distutils.build.Build
。這些命令類將繼承自 Command
類,該類(至少)將提供處理命令特定選項的方法。(Command
將提供一個建構函式,該建構函式接受 Distribution
類和此命令的可選引數列表,並透過檢查 Command
派生例項中的 getopt 樣式選項說明符來解析引數列表。)每個命令類必須提供一個 run
方法,該方法使用 Distribution
例項中的資訊和命令選項來“執行其操作”。編寫良好的命令類會將此任務分解為幾個定義明確(且有文件說明)的方法,以便客戶端 setup.py 可以繼承並覆蓋 Distutils 命令類的特定行為。這也意味著 Distribution
類必須有一種方法將覆蓋的命令類傳達給主排程程式。
客戶端的觀點
如上所述,客戶端 (setup.py) 只需匯入 distutils.core
—— 其他所有 Distutils 相關的功能都由這個核心模組處理。然而,客戶端需要一種方法將其特定選項傳遞給 Distutils 核心(並傳遞給命令模組)。
有兩種可能的方案:一種簡短方便(但擴充套件性不強),另一種有點冗長笨拙(但更面向物件且擴充套件性強)。我們沒有理由不能兩者兼得;方便的介面可以只是一個包裝器,用於許多不需要大量花哨自定義的模組分發。
首先,這是一個簡單介面的示例,用於包含單個“純 Python”模組 (mymod.py) 的模組分發。
from distutils.core import setup setup (name = "mymod", version = "1.2", author = "Greg Ward <gward@cnri.reston.va.us>", description = "A very simple, one-module distribution")請注意,我們沒有明確列出 mymod.py:Distutils 假設這是一個以其唯一模組 (
mymod
) 命名的單模組分發。
那些喜歡定義子類的人可能更喜歡以不同的方式表達
from distutils.core import Distribution, setup class MyDistribution (Distribution): name = "mymod" version = "1.2", author = "Greg Ward <gward@cnri.reston.va.us>", description = "A very simple, one-module distribution") setup (distclass = MyDistribution)對於小型分發來說,這有點矯枉過正:我們僅為了提供屬性值而定義一個新類,而
distutils.core.setup
的主要目的正是讓我們這樣做。儘管如此,面向物件純粹主義者會喜歡這一點——而且無疑會有客戶端必須覆蓋行為而不僅僅是資料的情況,屆時面向物件介面將是必要的。
對於更復雜的模組分發,需要自定義大量屬性,將其分解開來可能更容易閱讀/維護。考慮一個包含兩個純 Python 模組 (mymod
和 my_othermod
) 和一個 C 擴充套件 (myext
) 的分發;C 擴充套件必須與兩個輔助 C 檔案和一個 C 庫連結。哦,這個分發需要 Python 1.5 和任何版本的 re
模組(忽略一個通常意味著另一個的事實)
from distutils.core import Distribution, setup class MyDistribution (Distribution): name = "mydist", version = "1.3.4", author = "Greg Ward <gward@cnri.reston.va.us>" description = """\ This is an example module distribution. It provides no useful code, but is an interesting example of the Distutils in action.""" # Dependencies requires = { 'python': '1.5', # I like class-based exceptions 're': '*', # and I love Perl-style regexps! ;-) } # Actual files that need to be processed and installed in some form py_modules = ['mymod.py', 'my_othermod.py'], ext_modules = {'myext.c': {'other_c': ['extra1.c', 'extra2.c'], 'c_libraries': ['mylib']} } setup (distclass = MyDistribution)
有幾點需要注意
- 我不害怕使用深度巢狀的資料結構;如果您正在編寫和分發 Python 模組,這不應該是一個問題!
- 每個屬性都有一個特定的型別(字串、列表、字典等)
- 具有複雜型別(尤其是字典)的屬性將具有眾所周知且有文件說明的內部結構,例如。
"""ext_modules is a hash mapping names of C source files (each containing a Python extension module) to a nested hash of information about how to build that module. The allowed keys to this nested hash are: - other_c: other C files that must be compiled and linked with the main C file to create the module - c_libraries: C libraries that must be included in the link ... """
毫無疑問,ext_modules
巢狀雜湊將有更多選項,毫無疑問,其他 Distribution
屬性將具有複雜且有文件說明的結構。
最後,所有 Distribution
屬性的列表必須是眾所周知且有文件說明的!這些似乎分為幾個大類。這是一個最初的列表嘗試
- 分發元資料
名稱
版本
作者
描述
- 依賴項
requires
- 要處理和安裝的檔案
py_modules
ext_modules
doc_files
- 構建目錄(預設都在 ./blib 下)
build_lib
- 放置獨立於平臺的庫檔案的位置build_platlib
- 放置依賴於平臺的庫檔案的位置build_exe
- 放置可執行程式(即指令碼)的位置build_html
- 放置已處理文件(HTML)的位置
- 安裝目錄(預設在
sysconfig.LIBDEST
下)install_lib
install_platlib
install_exe
install_html
Distutils 的觀點再探
總而言之,讓我們回顧一下使用者執行 setup.py 時發生的事情。無論 setup.py 是以簡單形式(呼叫函式)還是通用形式(定義子類)編寫,都沒有太大關係,所以我不會將事情分成兩個流。
- setup.py 匯入
distutils.core
distutils.core
啟動程式碼解析命令列引數:處理它知道的全域性選項,並保留其餘部分供客戶端 (setup.py) 處理;找出每個命令的命令和選項,將它們都儲存起來以便稍後處理- setup.py 呼叫
distutils.core.setup
(可能帶有一個distclass
引數,指定Distribution
的子類,可能帶有一堆其他命名引數,指定Distribution
例項的各種屬性) distutils.core.setup
例項化Distribution
(或客戶端提供的子類),並使用其引數(除了distclass
)來覆蓋此例項的屬性distutils.core.setup
載入命令模組(例如distutils.build
)distutils.core.setup
確定命令類(通常僅以命令命名,例如distutils.build.Build
,但也可能是客戶端作為Distribution
例項的屬性之一提供的類)並例項化它- 命令類建構函式接受
Distribution
例項和 setup.py 命令列上特定於此命令的任何命令列引數作為引數 - 命令類建構函式解析其選項以設定/覆蓋某些例項屬性
distutils.core.setup
呼叫命令物件上的run
方法- 該方法執行命令應該執行的任何操作:構建模組、處理文件、安裝檔案等。
distutils.core.setup
確定下一個命令類(如果給定了多個命令),並像以前一樣進行