1. 程式人生 > >python中的setup.py詳解

python中的setup.py詳解

前言

其實對於setup.py和setup.cfg的關注是從OpenStack的原始碼包中開始的,OpenStack每個元件的釋出時都是一個tar.gz包,同樣,我們直接從github上clone程式碼後也會發現兩個檔案的存在。當閱讀Nova或Ceilometer(其他元件可能也會涉及)的程式碼時,發現setup.cfg中內容對於程式碼的理解有很大的影響。那麼,到底setup.py和setup.cfg是幹什麼的?

我們從例子開始。假設你要分發一個叫foo的模組,檔名foo.py,那麼setup.py內容如下:

  1. from distutils.core import setup
  2. setup(name='foo',
  3. version='1.0',
  4. py_modules=['foo'],
  5. )

然後,執行python setup.py sdist為模組建立一個原始碼包

  1. [email protected]:/kong/setup# python setup.py sdist
  2. running sdist
  3. running check
  4. warning: check: missing required meta-data: url
  5. warning: check: missing meta-data: either (author and author_email)or(
    maintainer and maintainer_email) must be supplied
  6. warning: sdist: manifest template'MANIFEST.in' does not exist (usingdefault file list)
  7. warning: sdist: standard file not found: should have one of README, README.txt
  8. writing manifest file 'MANIFEST'
  9. creating foo-1.0
  10. making hard links in foo-1.0...
  11. hard linking foo
    .py -> foo-1.0
  12. hard linking setup.py -> foo-1.0
  13. creating dist
  14. Creating tar archive
  15. removing 'foo-1.0'(and everything under it)

在當前目錄下,會建立dist目錄,裡面有個檔名為foo-1.0.tar.gz,這個就是可以分發的包(如果使用命令python setup.py bdist_egg,那麼會在dist目錄中生成foo-1.0-py2.7.egg包,setup.py中第一句引入需要改為from setuptools import setup)。使用者拿到這個包後,解壓,到foo-1.0目錄下執行:python setup.py install,那麼,foo.py就會被拷貝到python類路徑下,可以被匯入使用(如果安裝是egg檔案,會把egg檔案拷貝到dist-packages目錄下)。

  1. [email protected]:/kong/setup/dist/foo-1.0# python setup.py install
  2. running install
  3. running build
  4. running build_py
  5. creating build
  6. creating build/lib.linux-x86_64-2.7
  7. copying foo.py -> build/lib.linux-x86_64-2.7
  8. running install_lib
  9. copying build/lib.linux-x86_64-2.7/foo.py ->/usr/local/lib/python2.7/dist-packages
  10. byte-compiling /usr/local/lib/python2.7/dist-packages/foo.py to foo.pyc
  11. running install_egg_info
  12. Removing/usr/local/lib/python2.7/dist-packages/foo-1.0.egg-info
  13. Writing/usr/local/lib/python2.7/dist-packages/foo-1.0.egg-info
  14. [email protected]:/kong/setup/dist/foo-1.0# ll /usr/local/lib/python2.7/dist-packages/foo
  15. foo-1.0.egg-info foo.py foo.pyc

對於Windows,可以執行python setup.py bdist_wininst生成一個exe檔案;若要生成RPM包,執行python setup.py bdist_rpm,但系統必須有rpm命令的支援。可以執行下面的命令檢視所有格式的支援:

  1. [email protected]:/kong/setup# python setup.py bdist --help-formats
  2. List of available distribution formats:
  3. --formats=rpm RPM distribution
  4. --formats=gztar gzip'ed tar file
  5. --formats=bztar bzip2'ed tar file
  6. --formats=ztar compressed tar file
  7. --formats=tar tar file
  8. --formats=wininst Windows executable installer
  9. --formats=zip ZIP file
  10. --formats=msi MicrosoftInstaller

setup函式還有一些引數:

1、packages
告訴Distutils需要處理那些包(包含__init__.py的資料夾)
2、package_dir
告訴Distutils哪些目錄下的檔案被對映到哪個原始碼包,感覺好像是一個相對路徑的定義。一個例子:package_dir = {'': 'lib'},表示以lib為主目錄。
3、ext_modules
是一個包含Extension例項的列表,Extension的定義也有一些引數。
4、ext_package
定義extension的相對路徑
5、requires
定義依賴哪些模組
6、provides
定義可以為哪些模組提供依賴
7、scripts
指定python原始碼檔案,可以從命令列執行。在安裝時指定--install-script
8、package_data
通常包含與包實現相關的一些資料檔案或類似於readme的檔案。

  1. package_data ={'':['*.txt'],'mypkg':['data/*.dat'],}

表示包含所有目錄下的txt檔案和mypkg/data目錄下的所有dat檔案。

9、data_files
指定其他的一些檔案(如配置檔案)

  1. setup(...,
  2. data_files=[('bitmaps',['bm/b1.gif','bm/b2.gif']),
  3. ('config',['cfg/data.cfg']),
  4. ('/etc/init.d',['init-script'])]
  5. )

規定了哪些檔案被安裝到哪些目錄中。如果目錄名是相對路徑,則是相對於sys.prefixsys.exec_prefix的路徑。如果沒有提供模板,會被新增到MANIFEST檔案中。

執行sdist命令時,預設會打包哪些東西呢?

  • 所有由py_modulespackages指定的原始碼檔案
  • 所有由ext_moduleslibraries指定的C原始碼檔案
  • scripts指定的指令碼檔案
  • 類似於test/test*.py的檔案
  • README.txt或README,setup.py,setup.cfg
  • 所有package_datadata_files指定的檔案

還有一種方式是寫一個manifest template,名為MANIFEST.in,定義如何生成MANIFEST檔案,內容就是需要包含在分發包中的檔案。一個MANIFEST.in檔案如下:

  1. include *.txt
  2. recursive-include examples *.txt *.py
  3. prune examples/sample?/build

setup.cfg提供一種方式,可以讓包的開發者提供命令的預設選項,同時為使用者提供修改的機會。對setup.cfg的解析,是在setup.py之後,在命令列執行前。

setup.cfg檔案的形式類似於

  1. [command]
  2. option=value
  3. ...

其中,command是Distutils的命令引數,option是引數選項,可以通過python setup.py --help build_ext方式獲取。

需要注意的是,比如一個選項是--foo-bar,在setup.cfg中必須改成foo_bar的格式

符合Distutils2的setup.cfg有些不同。包含一些sections:
1、global
定義Distutils2的全域性選項,可能包含commands,compilers,setup_hook(定義指令碼,在setup.cfg被讀取後執行,可以修改setup.cfg的配置,pbr就用到了這個)
2、metadata
3、files

  • packages_root:根目錄
  • packages
  • modules
  • scripts
  • extra_files

上面的setup.py和setup.cfg都是遵循python標準庫中的Distutils,而setuptools工具針對Python官方的distutils做了很多針對性的功能增強,比如依賴檢查,動態擴充套件等。很多高階功能我就不詳述了,自己也沒有用過,等用的時候再作補充。詳情可參見這裡

一個典型的遵循setuptools的指令碼:

  1. from setuptools import setup, find_packages
  2. setup(
  3. name ="HelloWorld",
  4. version ="0.1",
  5. packages = find_packages(),
  6. scripts =['say_hello.py'],
  7. # Project uses reStructuredText, so ensure that the docutils get
  8. # installed or upgraded on the target machine
  9. install_requires =['docutils>=0.3'],
  10. package_data ={
  11. # If any package contains *.txt or *.rst files, include them:
  12. '':['*.txt','*.rst'],
  13. # include any *.msg files found in the 'hello' package, too:
  14. 'hello':['*.msg'],
  15. },
  16. # metadata for upload to PyPI
  17. author ="Me",
  18. author_email ="[email protected]",
  19. description ="This is an Example Package",
  20. license ="PSF",
  21. keywords ="hello world example examples",
  22. url ="http://example.com/HelloWorld/",# project home page, if any
  23. # could also include long_description, download_url, classifiers, etc.
  24. )

setuptools相對distutils,增強的關鍵字:
include_package_data:為True時自動新增受版本控制的資料檔案,可替代package_data,同時,exclude_package_data可以排除某些檔案。當你需要加入沒有被版本控制的檔案時,還是老老實實使用package_data吧。
install_requires:代替require函式。表示當前包的安裝依賴於哪些分發包,這些資訊會寫入egg的元資訊中,這些包在安裝時會自動(從PyPI)下載並安裝。如果包在PyPI中找不到,則會從dependency_links標識的URL中獲取。
extras_require:當前包的高階/額外特性需要依賴的分發包。
entry_points:這個很經典。見下面的講解。
setup_requires: 安裝指令碼執行時需要依賴的分發包,主要用於構建過程。注意,這裡列出的包不會自動安裝,如果需要,同時要在install_requires中指定。
dependency_links:URL地址。這些地址在安裝setup_requirestests_require指定的包時使用。會寫入egg的metadata資訊中。

  1. setup(
  2. # other arguments here...
  3. entry_points ={
  4. 'setuptools.installation':[
  5. 'eggsecutable = my_package.some_module:main_func',
  6. ]
  7. }
  8. )
  1. setup(
  2. name="Project-A",
  3. ...
  4. extras_require ={
  5. 'PDF':["ReportLab>=1.2","RXP"],
  6. 'reST':["docutils>=0.3"],
  7. 相關推薦

    pythonsetup.py

    前言 其實對於setup.py和setup.cfg的關注是從OpenStack的原始碼包中開始的,OpenStack每個元件的釋出時都是一個tar.gz包,同樣,我們直接從github上clone程式碼後也會發現兩個檔案的存在。當閱讀Nova或Ceilometer(其

    Pythonenumerate用法

    num readline 文件的 簡單 += () 用法 字符 計數 enumerate()是python的內置函數、適用於python2.x和python3.xenumerate在字典上是枚舉、列舉的意思enumerate參數為可遍歷/可叠代的對象(如列表、字符串)enu

    python閉包

    ner copy bsp div 執行 gpo 註意 outer 在一起 閉包這個概念好難理解,身邊朋友們好多都稀裏糊塗的,稀裏糊塗的林老冷希望寫下這篇文章能夠對稀裏糊塗的夥伴們有一些幫助~ 請大家跟我理解一下,如果在一個函數的內部定義了另一個函數,外部的我們叫

    python setup.py 使用方式

    #python setup.py --help-commands Standard commands: build:      build everything needed to install build_py:  

    聊聊Python的GIL python的GIL

    對於廣大寫Python的人來說,GIL(Global Interpreter Lock, 全域性直譯器鎖)肯定不陌生,但未必清楚GIL的歷史和全貌是怎樣的,今天我們就來梳理一下GIL。 1. 什麼是GIL GIL的全稱是 Global Interpreter Lock,全域性直譯器鎖。之所以叫這

    pythonsocket模組

    socket模組簡介 網路上的兩個程式通過一個雙向的通訊連線實現資料的交換,這個連線的一端稱為一個socket。socket通常被叫做“套接字”,用於描述IP地址和埠,是一個通訊鏈的控制代碼,可以用來實現不同虛擬機器或不同計算機之間的通訊。在Internet上的主機一般運行了多個服務

    pythonlist方法說明

    序號 分類 關鍵字/函式/方法 描述 1 新增 list.insert(索引,資料) 在指定位置插入資料     list.append(資料)

    Python的generator

    注:本文在原文基礎上做了一點點修改,僅僅作為個人理解與記憶,建議直接檢視原文。 generator使用場景:   1  當我們需要一個公用的,按需生成的資料   2  某個事情執行一部分,另一部分在某個事件發生後再執行下一部分,實現非同步。 注意事項:  

    pythonpsutil模組

             在Python中獲取系統資訊的另一個好辦法是使用psutil這個第三方模組。顧名思義,psutil = process and system utilities,它不僅可以通過一兩行程式碼實現系統監控,還可以跨平臺使用,支援Linu

    Python函式的

    Python中的函式作用跟其他語言的函式作用基本相同,都是帶名字的程式碼塊,用於一些完成具體的工作。 要執行函式定義的特殊任務,可呼叫該函式。需要在程式中,多次執行同一項任務的函式,無需反覆編寫完成該任務的程式碼,而只需要呼叫執行該任務的函式即可。 首先:定義一

    python的import

    標準的匯入模組 在python中所有載入到記憶體中的模組都存在於sys.modules 當 import 一個模組時首先會在這個列表中查詢是否已經載入了此模組: 如果載入了則只是將模組的名字加入到正在呼叫 import 的模組的 Local 名字空間中。 如果沒有載入則從

    pythonnew方法

    new_ 方法是什麼? __new__方法其實就是建立物件的方法 new()方法是在類準備將自身例項化時呼叫。 一個類可以有多個位置引數和多個命名引數,而在例項化開始之後,在呼叫 init()方法之前,Python首先呼叫new()方法: def new(cls, *args, **kw

    Pythonglobal用法

    1. 文件說明    在python3.3.2的官方api幫助文件上看到, 如下一段話: The global statement is a declaration which holds for the entire current code block. It mean

    Python字典(dict)

    python字典:   一個對映物件將可雜湊的值對映到任意物件。對映型別是可變的物件。當前只有一種標準的對映型別,即字典。用作鍵值的數字型別遵循正常的數值比較規則:如果兩個數是相等的(例如1和1.0),那麼它們可以交替使用來索引同一個字典條目。(但是注意,由於

    pythonlist操作

    1.定義list >>> li = ["a", "b", "mpilgrim", "z", "example"] >>> li ['a', 'b', 'mpilgrim', 'z', 'example'] >>> li[

    python裝飾器

    裝飾器 我們知道,在python中,我們可以像使用變數一樣使用函,這主要依賴於以下幾點: 函式可以被賦值給其他變數 函式可以被刪除 可以在函式裡面再定義函式,函式巢狀。 函式可以作為引數傳遞給另外一個函式 函式可以作為另一個函式的返回值 對一個簡單的函

    python字典dic-建立,遍歷和排序

    在python的程式設計中,字典dic是最典型的資料結構,看看如下對字典的操作: 建立字典 直接使用 {} 建立空字典: book_price = {} 直接初始化的方式建立字典: book_price = {'a':23,'b':30}

    pythondatetime模組

    timedelta timedelta的例項化 一個timedalta物件代表了一個時間差,當兩個date或datetime進行相減操作時會返回一個timedelta物件,或者,我們也可以手動對其進行例項化,其建構函式的原型如下: class datetime.timedelta([

    8.Djangoviews.py

    一 HttpRequest和HttpResponse HTTP請求:HttpRequest HTTP響應:HttpResponse 所在位置django.http 1 GET

    Pythonproperty屬性

    ring delet 暴露 span odi ret wan ise odin 1. 什麽是property屬性 一種用起來像是使用的實例屬性一樣的特殊屬性,可以對應於某個方法 # ############### 定義 ############### class