setuptools詳解

Python包管理工具setuptools詳解

前言:這篇是別人寫的虎忌,我這邊只是記錄下橱鹏,以后查資料的時候,更方便莉兰。

0.什么是setuptools

setuptools是Python distutils增強版的集合,它可以幫助我們更簡單的創(chuàng)建和分發(fā)Python包杉辙,尤其是擁有依賴關(guān)系的捶朵。用戶在使用setuptools創(chuàng)建的包時,并不需要已安裝setuptools综看,只要一個啟動模塊即可。

功能亮點:

  • 利用EasyInstall自動查找舞吭、下載、安裝蔑穴、升級依賴包
  • 創(chuàng)建Python Eggs
  • 包含包目錄內(nèi)的數(shù)據(jù)文件
  • 自動包含包目錄內(nèi)的所有的包惧浴,而不用在setup.py中列舉
  • 自動包含包內(nèi)和發(fā)布有關(guān)的所有相關(guān)文件,而不用創(chuàng)建一個MANIFEST.in文件
  • 自動生成經(jīng)過包裝的腳本或Windows執(zhí)行文件
  • 支持Pyrex赶舆,即在可以setup.py中列出.pyx文件,而最終用戶無須安裝Pyrex
  • 支持上傳到PyPI
  • 可以部署開發(fā)模式叙量,使項目在sys.path中
  • 用新命令或setup()參數(shù)擴展distutils九串,為多個項目發(fā)布/重用擴展
  • 在項目setup()中簡單聲明entry points,創(chuàng)建可以自動發(fā)現(xiàn)擴展的應(yīng)用和框架

總之猪钮,setuptools就是比distutils好用的多烤低,基本滿足大型項目的安裝和發(fā)布

1.安裝setuptools

1) 最簡單安裝,假定在ubuntu下
  • sudo apt-get install python-setuptools
2) 啟動腳本安裝

2.創(chuàng)建一個簡單的包

有了setuptools后扑馁,創(chuàng)建一個包基本上是無腦操作

cd /tmp 
mkdir demo
cd demo

在demo中創(chuàng)建一個setup.py文件,寫入


from setuptools import setup, find_packages
setup(
    name = "demo",
    version = "0.1",
    packages = find_packages(),
)

執(zhí)行python setup.py bdist_egg即可打包一個test的包了复罐。

demo
|-- build
|   `-- bdist.linux-x86_64
|-- demo.egg-info
|   |-- dependency_links.txt
|   |-- PKG-INFO
|   |-- SOURCES.txt
|   `-- top_level.txt
|-- dist
|   `-- demo-0.1-py2.7.egg
`-- setup.py

在dist中生成的是egg包

file dist/demo-0.1-py2.7.egg
dist/demo-0.1-py2.7.egg: Zip archive data, at least v2.0 to extract

看一下生成的.egg文件雄家,是個zip包,解開看看先

upzip -l dist/demo-0.1-py2.7.egg

Archive:  dist/demo-0.1-py2.7.egg
  Length      Date    Time    Name
---------  ---------- -----   ----
        1  2013-06-07 22:03   EGG-INFO/dependency_links.txt
        1  2013-06-07 22:03   EGG-INFO/zip-safe
      120  2013-06-07 22:03   EGG-INFO/SOURCES.txt
        1  2013-06-07 22:03   EGG-INFO/top_level.txt
      176  2013-06-07 22:03   EGG-INFO/PKG-INFO
---------                     -------
      299                     5 files

我們可以看到乱投,里面是一系列自動生成的文件×茫現(xiàn)在可以介紹一下剛剛setup()中的參數(shù)了

name 包名
version 版本號
packages 所包含的其他包

要想發(fā)布到PyPI中,需要增加別的參數(shù)勾效,這個可以參考官方文檔中的例子了。

3.給包增加內(nèi)容
上面生成的egg中沒有實質(zhì)的內(nèi)容杨伙,顯然誰也用不了,現(xiàn)在我們稍微調(diào)色一下抖苦,增加一點內(nèi)容米死。

在demo中執(zhí)行mkdir demo,再創(chuàng)建一個目錄峦筒,在這個demo目錄中創(chuàng)建一個init.py的文件,表示這個目錄是一個包卤材,然后寫入:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

def test():
    print "hello world!"  

if __name__ == '__main__':
    test()
    

現(xiàn)在的主目錄結(jié)構(gòu)為下:

demo
|-- demo
|   `-- __init__.py
`-- setup.py
再次執(zhí)行python setup.py bdist_egg后峦失,再看egg包

Archive:  dist/demo-0.1-py2.7.egg
  Length      Date    Time    Name
---------  ---------- -----   ----
        1  2013-06-07 22:23   EGG-INFO/dependency_links.txt
        1  2013-06-07 22:23   EGG-INFO/zip-safe
      137  2013-06-07 22:23   EGG-INFO/SOURCES.txt
        5  2013-06-07 22:23   EGG-INFO/top_level.txt
      176  2013-06-07 22:23   EGG-INFO/PKG-INFO
       95  2013-06-07 22:21   demo/__init__.py
      338  2013-06-07 22:23   demo/__init__.pyc
---------                     -------
      753                     7 files
 

這回包內(nèi)多了demo目錄,顯然已經(jīng)有了我們自己的東西了尉辑,安裝體驗一下材蹬。

python setup.py install

這個命令會講我們創(chuàng)建的egg安裝到python的dist-packages目錄下,我這里的位置在

tree /usr/local/lib/python2.7/dist-packages/demo-0.1-py2.7.egg

查看一下它的結(jié)構(gòu):


/usr/local/lib/python2.7/dist-packages/demo-0.1-py2.7.egg
|-- demo
|   |-- __init__.py
|   `-- __init__.pyc
`-- EGG-INFO
    |-- dependency_links.txt
    |-- PKG-INFO
    |-- SOURCES.txt
    |-- top_level.txt
    `-- zip-safe
    

打開python終端或者ipython都行堤器,直接導(dǎo)入我們的包

>>> import demo
>>> demo.test()
hello world!
>>>

好了末贾,執(zhí)行成功!

4.setuptools進階

在上例中辉川,在前兩例中拴测,我們基本都使用setup()的默認(rèn)參數(shù),這只能寫一些簡單的egg集索。一旦我們的project逐漸變大以后汇跨,維護起來就有點復(fù)雜了妆距,下面是setup()的其他參數(shù),我們可以學(xué)習(xí)一下

使用find_packages()
對于簡單工程來說蚪黑,手動增加packages參數(shù)很容易中剩,剛剛我們用到了這個函數(shù),它默認(rèn)在和setup.py同一目錄下搜索各個含有init.py的包伴网。其實我們可以將包統(tǒng)一放在一個src目錄中妆棒,另外,這個包內(nèi)可能還有aaa.txt文件和data數(shù)據(jù)文件夾糕珊。

demo
├── setup.py
└── src
    └── demo
        ├── __init__.py
        ├── aaa.txt
        └── data
            ├── abc.dat
            └── abcd.dat
            

如果不加控制,則setuptools只會將init.py加入到egg中澜公,想要將這些文件都添加喇肋,需要修改setup.py

from setuptools import setup, find_packages
setup(
    packages = find_packages('src'),  # 包含所有src中的包
    package_dir = {'':'src'},   # 告訴distutils包都在src下

    package_data = {
        # 任何包中含有.txt文件,都包含它
        '': ['*.txt'],
        # 包含demo包data文件夾中的 *.dat文件
        'demo': ['data/*.dat'],
    }
)

這樣蝶防,在生成的egg中就包含了所需文件了间学。看看:


Archive:  dist/demo-0.0.1-py2.7.egg
  Length     Date   Time    Name
 --------    ----   ----    ----
       88  06-07-13 23:40   demo/__init__.py
      347  06-07-13 23:52   demo/__init__.pyc
        0  06-07-13 23:45   demo/aaa.txt
        0  06-07-13 23:46   demo/data/abc.dat
        0  06-07-13 23:46   demo/data/abcd.dat
        1  06-07-13 23:52   EGG-INFO/dependency_links.txt
      178  06-07-13 23:52   EGG-INFO/PKG-INFO
      157  06-07-13 23:52   EGG-INFO/SOURCES.txt
        5  06-07-13 23:52   EGG-INFO/top_level.txt
        1  06-07-13 23:52   EGG-INFO/zip-safe
 --------                   -------
      777                   10 files

另外低葫,也可以排除一些特定的包,如果在src中再增加一個tests包实柠,可以通過exclude來排除它,

find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"])

使用entry_points

一個字典善涨,從entry point組名映射道一個表示entry point的字符串或字符串列表草则。Entry points是用來支持動態(tài)發(fā)現(xiàn)服務(wù)和插件的登钥,也用來支持自動生成腳本。這個還是看例子比較好理解:

setup(
    entry_points = {
        'console_scripts': [
            'foo = demo:test',
            'bar = demo:test',
        ],
        'gui_scripts': [
            'baz = demo:test',
        ]
    }
)

修改setup.py增加以上內(nèi)容以后看锉,再次安裝這個egg塔鳍,可以發(fā)現(xiàn)在安裝信息里頭多了兩行代碼(Linux下):

Installing foo script to /usr/local/bin
Installing bar script to /usr/local/bin

查看/usr/local/bin/foo內(nèi)容

#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'demo==0.1','console_scripts','foo'
__requires__ = 'demo==0.1'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('demo==0.1', 'console_scripts', 'foo')()
    )
    

這個內(nèi)容其實顯示的意思是,foo將執(zhí)行console_scripts中定義的foo所代表的函數(shù)腔寡。執(zhí)行foo,發(fā)現(xiàn)打出了hello world!放前,和預(yù)期結(jié)果一樣糯彬。

使用Eggsecutable Scripts
從字面上來理解這個詞,Eggsecutable是Eggs和executable合成詞撩扒,翻譯過來就是另eggs可執(zhí)行搓谆。也就是說定義好一個參數(shù)以后,可以另你生成的.egg文件可以被直接執(zhí)行泉手,貌似Java的.jar也有這機制?不很清楚啡氢,下面是使用方法:

setup(
    # other arguments here...
    entry_points = {
        'setuptools.installation': [
            'eggsecutable = demo:test',
        ]
    }
)

這么寫意味著在執(zhí)行python *.egg時术裸,會執(zhí)行我的test()函數(shù)亭枷,在文檔中說需要將.egg放到PATH路徑中。

包含數(shù)據(jù)文件
在3中我們已經(jīng)列舉了如何包含數(shù)據(jù)文件叨粘,其實setuptools提供的不只這么一種方法瘤睹,下面是另外兩種

1)包含所有包內(nèi)文件

這種方法中包內(nèi)所有文件指的是受版本控制(CVS/SVN/GIT等)的文件答倡,或者通過MANIFEST.in聲明的

from setuptools import setup, find_packages
setup(
    ...
    include_package_data = True
)

2)包含一部分,排除一部分

from setuptools import setup, find_packages
setup(
    ...
    packages = find_packages('src'),  
    package_dir = {'':'src'},   

    include_package_data = True,    

    # 排除所有 README.txt
    exclude_package_data = { '': ['README.txt'] },
)

如果沒有使用版本控制的話获茬,可以還是使用3中提到的包含方法

可擴展的框架和應(yīng)用
setuptools可以幫助你將應(yīng)用變成插件模式倔既,供別的應(yīng)用使用。官網(wǎng)舉例是一個幫助博客更改輸出類型的插件渤涌,一個博客可能想要輸出不同類型的文章,但是總自己寫輸出格式化代碼太繁瑣茸俭,可以借助一個已經(jīng)寫好的應(yīng)用安皱,在編寫博客程序的時候動態(tài)調(diào)用其中的代碼。

通過entry_points可以定義一系列接口练俐,供別的應(yīng)用或者自己調(diào)用腺晾,例如:

setup(
    entry_points = {'blogtool.parsers': '.rst = some_module:SomeClass'}
)

setup(
    entry_points = {'blogtool.parsers': ['.rst = some_module:a_func']}
)

setup(
    entry_points = """
        [blogtool.parsers]
        .rst = some.nested.module:SomeClass.some_classmethod [reST]
    """,
    extras_require = dict(reST = "Docutils>=0.3.5")
)

上面列舉了三中定義方式,即我們將我們some_module中的函數(shù)悯蝉,以名字為blogtool.parsers的借口共享給別的應(yīng)用。

別的應(yīng)用使用的方法是通過pkg_resources.require()來導(dǎo)入這些模塊暇榴。

另外,一個名叫stevedore的庫將這個方式做了封裝蕉世,更加方便進行應(yīng)用的擴展蔼紧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狠轻,隨后出現(xiàn)的幾起案子奸例,更是在濱河造成了極大的恐慌,老刑警劉巖向楼,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查吊,死亡現(xiàn)場離奇詭異谐区,居然都是意外死亡,警方通過查閱死者的電腦和手機逻卖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來评也,“玉大人炼杖,你說我怎么就攤上這事〕鸩危” “怎么了嘹叫?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長诈乒。 經(jīng)常有香客問我罩扇,道長,這世上最難降的妖魔是什么怕磨? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任喂饥,我火速辦了婚禮,結(jié)果婚禮上肠鲫,老公的妹妹穿的比我還像新娘员帮。我一直安慰自己,他們只是感情好导饲,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布捞高。 她就那樣靜靜地躺著,像睡著了一般渣锦。 火紅的嫁衣襯著肌膚如雪硝岗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天袋毙,我揣著相機與錄音型檀,去河邊找鬼。 笑死听盖,一個胖子當(dāng)著我的面吹牛胀溺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播皆看,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼仓坞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腰吟?” 一聲冷哼從身側(cè)響起扯躺,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝎困,沒想到半個月后录语,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡禾乘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年澎埠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片始藕。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蒲稳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伍派,到底是詐尸還是另有隱情江耀,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布诉植,位于F島的核電站祥国,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏晾腔。R本人自食惡果不足惜舌稀,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灼擂。 院中可真熱鬧壁查,春花似錦、人聲如沸剔应。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽峻贮。三九已至席怪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間月洛,已是汗流浹背何恶。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嚼黔,地道東北人细层。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像唬涧,于是被迫代替她去往敵國和親疫赎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容