6. Distutils 示例?
備注
這篇文檔是歷史遺留文檔,在 https://setuptools.readthedocs.io/en/latest/setuptools.html 上的 setuptools
文檔獨立涵蓋此處包含的所有相關(guān)信息之后,將不再單獨作為正式文檔保留。
本章節(jié)提供幾個基礎(chǔ)示例,來幫助用戶入門 distutils。關(guān)于使用 distutils 的額外信息可以參考 Distutils Cookbook。
參見
- Distutils Cookbook
一套展示如何更好地控制和使用 distutils 的方法。
6.1. 純 Python 分發(fā)(通過 module)?
如果你要分發(fā)一組模塊,特別是它們不在特定的包中,你可以在配置腳本中使用 py_modules
選項單獨指定它們。
最簡單的情況下,你只用關(guān)心兩個文件:一個配置腳本,和單個你要分發(fā)的模塊,這個示例中的 foo.py
: :
<root>/
setup.py
foo.py
(在本章節(jié)的所有圖中,<root> 表示分發(fā)根目錄。)這種情況下的一個最小配置腳本是:
from distutils.core import setup
setup(name='foo',
version='1.0',
py_modules=['foo'],
)
注意分發(fā)的包名用 name
選項單獨指定,沒有規(guī)定它必須和包中單獨的模塊同名(雖然這也是個可以遵循的好習慣)。然而,分發(fā)名用來生成文件名,所以你應(yīng)該堅持用字母、數(shù)字、下劃線和連詞號。
因為 py_modules
是個列表,你當然可以指定多個模塊,比如,如果你要分發(fā)模塊 foo
和 bar
,你的配置可能是這樣:
<root>/
setup.py
foo.py
bar.py
并且配置腳本是:
from distutils.core import setup
setup(name='foobar',
version='1.0',
py_modules=['foo', 'bar'],
)
你可以把模塊源文件放進另一個目錄,但是如果你有足夠的模塊,也許用包指定模塊更簡單,而不是單獨列出它們。
6.2. 純 Python 分發(fā)(通過 包)?
如果你有超過一組模塊要分發(fā),特別是它們在不同的包中,也許指定整個包更簡單,而不是指定單獨的模塊。這樣即使你的模塊不在一個包中也有效;你可以直接令 Distutils 來從根包來處理模塊,并且這樣對任何其他包也有效(除非你不需要 __init__.py
文件)。
上一個示例的配置腳本也可以寫成:
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=[''],
)
(空字符串表示根包。)
如果兩個文件移動到子目錄,但是依然在根包中,如:
<root>/
setup.py
src/ foo.py
bar.py
那么你依然需要指定根包,但是你還需要告訴 Distutils 根包中的源文件在哪:
from distutils.core import setup
setup(name='foobar',
version='1.0',
package_dir={'': 'src'},
packages=[''],
)
更一般地,你要分發(fā)多個在同一個包(或者子包)中的模塊。舉個例子,假設(shè) foo
和 bar
模塊屬于 foobar
包,排布源文件樹的一種方式是:
<root>/
setup.py
foobar/
__init__.py
foo.py
bar.py
這其實是 Distutils 默認的排布,也是你的配置腳本中需要的工作量最小的。
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=['foobar'],
)
如果你要把模塊放到?jīng)]有按照它們的包名命名的目錄里,那你需要再次使用 package_dir
選項。比如,如果 src
目錄包含包 foobar
中的模塊:
<root>/
setup.py
src/
__init__.py
foo.py
bar.py
一個合適的配置腳本可以是:
from distutils.core import setup
setup(name='foobar',
version='1.0',
package_dir={'foobar': 'src'},
packages=['foobar'],
)
或者,你可以把主包中的模塊直接放到分發(fā)根目錄:
<root>/
setup.py
__init__.py
foo.py
bar.py
這樣你的配置文件是:
from distutils.core import setup
setup(name='foobar',
version='1.0',
package_dir={'foobar': ''},
packages=['foobar'],
)
(空字符串同樣表示當前目錄。)
如果你有子包,則它們必須顯式列在 packages
中,但是 package_dir
中的任何條目會自動擴展到子包。(也就是說,Distutils 不會 掃描你的源碼樹,而是嘗試通過查找 __init__.py
文件,來弄清哪些目錄與 Python 包關(guān)聯(lián)。)這樣,如果默認排布產(chǎn)生一個子包:
<root>/
setup.py
foobar/
__init__.py
foo.py
bar.py
subfoo/
__init__.py
blah.py
則相應(yīng)的配置腳本是:
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=['foobar', 'foobar.subfoo'],
)
6.3. 單個擴展模塊?
擴展模塊用 ext_modules
選項指定。package_dir
對在哪尋找擴展源文件無效;它只對純 Python 模塊的源文件有效。最簡單的,一個用單個C源文件寫的單擴展模塊是:
<root>/
setup.py
foo.c
如果 foo
擴展屬于根包,則配置腳本可以是:
from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
version='1.0',
ext_modules=[Extension('foo', ['foo.c'])],
)
如果擴展在包中,比如 foopkg
,那么
使用完全相同的源文件樹排布,通過改變擴展的名字,這個擴展很容易放入 foopkg
包中:
from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
version='1.0',
ext_modules=[Extension('foopkg.foo', ['foo.c'])],
)
6.4. 檢查一個包?
check
命令允許你校驗你的包的元數(shù)據(jù)是否滿足生成分發(fā)的最低要求。
直接使用你的 setup.py
腳本來運行它。如果缺了一些東西,check
會顯示警告。
我們來用單個腳本舉例:
from distutils.core import setup
setup(name='foobar')
運行 check
命令會顯示一些警告:
$ python setup.py check
running check
warning: check: missing required meta-data: version, url
warning: check: missing meta-data: either (author and author_email) or
(maintainer and maintainer_email) should be supplied
如果你在 long_description
域中使用 reStructuredText 語法,并且安裝了 docutils ,你可以用 check
命令,和 restructuredtext
選項檢查語法是否正確。
比如,如果 setup.py
腳本改成:
from distutils.core import setup
desc = """\
My description
==============
This is the description of the ``foobar`` package.
"""
setup(name='foobar', version='1', author='tarek',
author_email='tarek@ziade.org',
url='http://example.com', long_description=desc)
長描述中有問題的地方,通過使用 docutils
解析器,check
能進行刪除:
$ python setup.py check --restructuredtext
running check
warning: check: Title underline too short. (line 2)
warning: check: Could not finish the parsing.
6.5. 讀取元數(shù)據(jù)?
distutils.core.setup()
函數(shù)提供一個通過項目的 setup.py
腳本,來查詢項目的元數(shù)據(jù)的域的命令行接口:
$ python setup.py --name
distribute
這個調(diào)用通過運行 distutils.core.setup()
函數(shù)讀取 name
元數(shù)據(jù)。然而,當源文件或者二進制分發(fā)用 Distutils 創(chuàng)建時,元數(shù)據(jù)域?qū)懭胍粋€名為 PKG-INFO
的靜態(tài)文件。當一個基于Distutils的項目安裝在 Python 中時,PKG-INFO
文件隨著分發(fā)的模塊和包一起復制到 NAME-VERSION-pyX.X.egg-info
中,其中 NAME
是項目的名字,VERSION
是元數(shù)據(jù)中定義的版本, pyX.X
則是 Python 的大版本和小版本,如 2.7
或者 3.2
。
你可以讀回靜態(tài)文件,使用 distutils.dist.DistributionMetadata
類和它的 read_pkg_file()
方法:
>>> from distutils.dist import DistributionMetadata
>>> metadata = DistributionMetadata()
>>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
>>> metadata.name
'distribute'
>>> metadata.version
'0.6.8'
>>> metadata.description
'Easily download, build, install, upgrade, and uninstall Python packages'
注意類也可以用元數(shù)據(jù)文件載入值來實例化:
>>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
>>> DistributionMetadata(pkg_info_path).name
'distribute'