您的位置:首页 > 编程语言 > Python开发

Python打包、安装与发布工具--setuptools

2010-04-01 17:10 871 查看
Python中的setuptools工具不仅仅是简化了distutils的setup.py文件的编写,更重要的是它的包管理能力方面的增强。它可以使用一种更加透明的方法来查找、下载并安装依赖包;并可以在一个包的多个版本中自由进行切换,这些版本都安装在同一个系统上;也可以声明对某个包的特定版本的需求;还可以只使用一个简单的命令就能更新到某个包的最新版本。说白了,这个和java中的Maven,以及在centos中使用的Yum有相似的地方;下面,先对以下几个名词作一个解释:

1.distutils

distutils
(1)PartofthePythonstandardlibrarysinceversion1.6(自1.6版本,加入python标准库)
(2)Thestandardwayofbuildingandinstallingpackages(构建、安装包的标准方法)
(3)Primaryfunctionalityindistutils.core
(4)Developerorpackagercreatessetup.py

#!/usr/bin/envpython
fromdistutils.coreimportsetup
setup(name=“foo”,
version=“1.0”,
py_modules=[“foo”])
$pythonsetup.pysdist(createasourcedistribution)
$pythonsetup.pybdist(createabuilddistribution)
$pythonsetup.pyinstall(installusingdefaults)
*Other--install-*options(remembertoupdate$PYTHONPATH)

setup中的参数说明:

setup(arguments)
Thebasicdo-everythingfunctionthatdoesmosteverythingyoucouldeveraskforfromaDistutilsmethod.SeeXXXXX
Thesetupfunctiontakesalargenumberofarguments.Thesearelaidoutinthefollowingtable.

argumentnamevaluetype
nameThenameofthepackageastring
versionTheversionnumberofthepackageSeedistutils.version
descriptionAsinglelinedescribingthepackageastring
long_descriptionLongerdescriptionofthepackageastring
authorThenameofthepackageauthorastring
author_emailTheemailaddressofthepackageauthorastring
maintainerThenameofthecurrentmaintainer,ifdifferentfromtheauthorastring
maintainer_emailTheemailaddressofthecurrentmaintainer,ifdifferentfromtheauthor
urlAURLforthepackage(homepage)aURL
download_urlAURLtodownloadthepackageaURL
packagesAlistofPythonpackagesthatdistutilswillmanipulatealistofstrings
py_modulesAlistofPythonmodulesthatdistutilswillmanipulatealistofstrings
scriptsAlistofstandalonescriptfilestobebuiltandinstalledalistofstrings
ext_modulesAlistofPythonextensionstobebuiltAlistofinstancesofdistutils.core.Extension
classifiersAlistofcategoriesforthepackageThelistofavailablecategorizationsisathttp://cheeseshop.python.org/pypi?:action=list_classifiers.
distclasstheDistributionclasstouseAsubclassofdistutils.core.Distribution
script_nameThenameofthesetup.pyscript-defaultsto
sys.argv[0]
astring
script_argsArgumentstosupplytothesetupscriptalistofstrings
optionsdefaultoptionsforthesetupscriptastring
licenseThelicenseforthepackage
keywordsDescriptivemeta-data.SeePEP314
platforms
cmdclassAmappingofcommandnamestoCommandsubclassesadictionary
2.setuptools
1)AcollectionofenhancementstothePythondistutilspackagethatallowonetomoreeasilybuildand
distributepythonpackages(对distutils包的增强,使用setuptools可以更加方便的构建、发布pythonpackages)
2)Additionalsetofkeywordargumentstosetup()(在distutils.core.setup的基础上,添加了一些新的参数)
3)Includeseasy_install.py(包括一个easy_install.py工具,提供类似centos中的yum安装工具)
4)Createseggs(.egg)(关于egg,最好的解释还是:‘EggsaretoPythonsasJarsaretoJava…‘)
5)Featuresfordevelopers(e.g.supportfordatafiles,MANIFEST,Pyrex,PyPIupload,…)
6)Abilitytodeployprojectin“developmentmode”viasetup.pydevelopcommand.

3.egg文件

Eggs

“EggsaretoPythonsasJarsaretoJava…”------------PhillipJ.Eby
(1)Single-fileimportabledistributionformat.(这句话的意思是说,python中导入挂钩的更改,只要把egg加入到PYTHONPATH或者sys.path中,就可以像往常一样导入)
(2)EggsareZipfilesusingthe.eggextension,thatsupportincludingdataandCextensionsaswellasPythoncode

(egg也不一定是zipfile,setup的参数中有一个zip_safe参数,在程序打包时决定是否压缩,如果不指定,bdist_egg会对工程中的每一个文件作检查,具体的解释如下:)

zip_safeAboolean(TrueorFalse)flagspecifyingwhethertheprojectcanbesafelyinstalledandrunfromazipfile.Ifthisargumentisnotsupplied,thebdist_eggcommandwillhavetoanalyzeallofyourproject'scontentsforpossibleproblemseachtimeitbuidsanegg.
(关于egg中是否会打包.py以外的数据、文件,在setup中有3个参数控制,具体如下:)

include_package_dataIfsettoTrue,thistellssetuptoolstoautomaticallyincludeanydatafilesitfindsinsideyourpackagedirectories,thatareeitherunderCVSorSubversioncontrol,orwhicharespecifiedbyyourMANIFEST.infile.Formoreinformation,seethesectionbelowonIncludingDataFiles.exclude_package_dataAdictionarymappingpackagenamestolistsofglobpatternsthatshouldbeexcludedfromyourpackagedirectories.Youcanusethistotrimbackanyexcessfilesincludedbyinclude_package_data.Foracompletedescriptionandexamples,seethesectionbelowonIncludingDataFiles.package_dataAdictionarymappingpackagenamestolistsofglobpatterns.Foracompletedescriptionandexamples,seethesectionbelowonIncludingDataFiles.Youdonotneedtousethisoptionifyouareusinginclude_package_data,unlessyouneedtoadde.g.filesthataregeneratedbyyoursetupscriptandbuildprocess.(Andarethereforenotinsourcecontrolorarefilesthatyoudon'twanttoincludeinyoursourcedistribution.)
这里有一个例子:

IncludingDataFiles

Thedistutilshavetraditionallyallowedinstallationof"datafiles",whichareplacedinaplatform-specificlocation.However,themostcommonusecasefordatafilesdistributedwithapackageisforusebythepackage,usuallybyincludingthedatafilesinthepackagedirectory.

Setuptoolsoffersthreewaystospecifydatafilestobeincludedinyourpackages.First,youcansimplyusetheinclude_package_datakeyword,e.g.:

fromsetuptoolsimportsetup,find_packages
setup(
...
include_package_data=True
)

Thistellssetuptoolstoinstallanydatafilesitfindsinyourpackages.ThedatafilesmustbeunderCVSorSubversioncontrol,orelsetheymustbespecifiedviathedistutils'MANIFEST.infile.(Theycanalsobetrackedbyanotherrevisioncontrolsystem,usinganappropriateplugin.SeethesectionbelowonAddingSupportforOtherRevisionControlSystemsforinformationonhowtowritesuchplugins.)

Ifyouwantfiner-grainedcontroloverwhatfilesareincluded(forexample,ifyouhavedocumentationfilesinyourpackagedirectoriesandwanttoexcludethemfrominstallation),thenyoucanalsousethepackage_datakeyword,e.g.:

fromsetuptoolsimportsetup,find_packages
setup(
...
package_data={
#Ifanypackagecontains*.txtor*.rstfiles,includethem:
'':['*.txt','*.rst'],
#Andincludeany*.msgfilesfoundinthe'hello'package,too:
'hello':['*.msg'],
}
)

Thepackage_dataargumentisadictionarythatmapsfrompackagenamestolistsofglobpatterns.Theglobsmayincludesubdirectorynames,ifthedatafilesarecontainedinasubdirectoryofthepackage.Forexample,ifthepackagetreelookslikethis:

setup.py
src/
mypkg/
__init__.py
mypkg.txt
data/
somefile.dat
otherdata.dat

Thesetuptoolssetupfilemightlooklikethis:

fromsetuptoolsimportsetup,find_packages
setup(
...
packages=find_packages('src'),#includeallpackagesundersrc
package_dir={'':'src'},#telldistutilspackagesareundersrc

package_data={
#Ifanypackagecontains*.txtfiles,includethem:
'':['*.txt'],
#Andincludeany*.datfilesfoundinthe'data'subdirectory
#ofthe'mypkg'package,also:
'mypkg':['data/*.dat'],
}
)

Noticethatifyoulistpatternsinpackage_dataundertheemptystring,thesepatternsareusedtofindfilesineverypackage,evenonesthatalsohavetheirownpatternslisted.Thus,intheaboveexample,themypkg.txtfilegetsincludedeventhoughit'snotlistedinthepatternsformypkg.

Alsonoticethatifyouusepaths,youmustuseaforwardslash(/)asthepathseparator,evenifyouareonWindows.Setuptoolsautomaticallyconvertsslashestoappropriateplatform-specificseparatorsatbuildtime.

(Note:althoughthepackage_dataargumentwaspreviouslyonlyavailableinsetuptools,itwasalsoaddedtothePythondistutilspackageasofPython2.4;thereissomedocumentationforthefeatureavailableonthepython.orgwebsite.)

Sometimes,theinclude_package_dataorpackage_dataoptionsalonearen'tsufficienttopreciselydefinewhatfilesyouwantincluded.Forexample,youmaywanttoincludepackageREADMEfilesinyourrevisioncontrolsystemandsourcedistributions,butexcludethemfrombeinginstalled.So,setuptoolsoffersanexclude_package_dataoptionaswell,thatallowsyoutodothingslikethis:

fromsetuptoolsimportsetup,find_packages
setup(
...
packages=find_packages('src'),#includeallpackagesundersrc
package_dir={'':'src'},#telldistutilspackagesareundersrc

include_package_data=True,#includeeverythinginsourcecontrol

#...butexcludeREADME.txtfromallpackages
exclude_package_data={'':['README.txt']},
)

Theexclude_package_dataoptionisadictionarymappingpackagenamestolistsofwildcardpatterns,justlikethepackage_dataoption.And,justaswiththatoption,akeyof''willapplythegivenpattern(s)toallpackages.However,anyfilesthatmatchthesepatternswillbeexcludedfrominstallation,eveniftheywerelistedinpackage_dataorwereincludedasaresultofusinginclude_package_data.

Insummary,thethreeoptionsallowyouto:

include_package_dataAcceptalldatafilesanddirectoriesmatchedbyMANIFEST.inorfoundinsourcecontrol.package_dataSpecifyadditionalpatternstomatchfilesanddirectoriesthatmayormaynotbematchedbyMANIFEST.inorfoundinsourcecontrol.exclude_package_dataSpecifypatternsfordatafilesanddirectoriesthatshouldnotbeincludedwhenapackageisinstalled,eveniftheywouldotherwisehavebeenincludedduetotheuseoftheprecedingoptions.
NOTE:Duetothewaythedistutilsbuildprocessworks,adatafilethatyouincludeinyourprojectandthenstopincludingmaybe"orphaned"inyourproject'sbuilddirectories,requiringyoutorunsetup.pyclean--alltofullyremovethem.ThismayalsobeimportantforyourusersandcontributorsiftheytrackintermediaterevisionsofyourprojectusingSubversion;besuretoletthemknowwhenyoumakechangesthatremovefilesfrominclusionsotheycanrunsetup.pyclean--all.

(3)RequiresPython2.3orabove

(4)Eggsarebuiltusingthesetuptoolspackage;eg:

python2.4setup.pybdist_egg
(5)ThepublishedplanistoproposeinclusioninthePython2.5standardlibrary.(这个计划没有实现)
这个是我在http://www.ibm.com/developerworks/cn/linux/l-cppeak3.html上节选过来的,说的很好:

egg是一个包含所有包数据的文件包。在理想情况中,egg是一个使用zip压缩的文件,其中包括了所有需要的包文件。但是在某些情况下,
setuptools
会决定(或被开关告知)包不应该是zip压缩的。在这些情况下,egg只是一个简单的未曾压缩的子目录,但是里面的内容是相同的。使用单一的版本可以方便地进行转换,并可以节省一点磁盘空间,但是egg目录从功能和组织结构上来说都是相同的。一直使用JAR文件的Java™技术的用户会发现egg非常熟悉。

由于最新的Python版本中(需要2.3.5+或2.4)导入挂钩的更改,可以简单地通过设置
PYTHONPATH
sys.path
并像往常一样导入相应的包来使用egg。如果希望采用这种方法,就不需要使用
setuptools
ez_setup.py
了。例如,在本文使用的工作目录中,我就为PyYAML包放入了一个egg。现在我就可以使用这个包了,方法如下:

%exportPYTHONPATH=~/work/dW/PyYAML-3.01-py2.4.egg
%python-c'importyaml;printyaml.dump({"foo":"bar",1:[2,3]})'

1:[2,3]
foo:bar


(在这个地方,我想说一下,你必须使用过setuptools才会有eazy-install.pth)

不过,
PYTHONPATH
的(或者脚本或Pythonshell会话内的
sys.path
的)这种操作有些脆弱。egg的发现最好是在新一点的.pth文件中进行。在site-packages/或
PYTHONPATH
中的任何.pth文件都会进行解析来执行其他导入操作,其方法类似于检查可能包含包的那些目录位置一样。如果使用
setuptools
来处理包的管理功能,那么在安装、更新、删除包时,就需要修改一个名为easy-install.pth的文件。而且可以按照自己喜欢的方式对这个.pth进行命名(只要其扩展名是.pth即可)。例如,下面是我的easy-install.pth文件的内容:

%cat/sw/lib/python2.4/site-packages/easy-install.pth
importsys;sys.__plen=len(sys.path)
setuptools-0.6b1-py2.4.egg
SQLObject-0.7.0-py2.4.egg
FormEncode-0.5.1-py2.4.egg
Gnosis_Utils-1.2.1-py2.4.egg
importsys;new=sys.path[sys.__plen:];delsys.path[sys.__plen:];
p=getattr(sys,'__egginsert',0);sys.path[p:p]=new;
sys.__egginsert=p+len(new)

这种格式有点特殊:它近似于一个Python脚本,但却不完全是。需要说明的是,可以在那里添加额外列出的egg;更好的情况是,
easy_install
会在运行时实现这种功能。也可以在site-packages/下创建任意多个.pth文件;每个都可以列出有哪些egg是可用的。

WhybotherwithEggs?
1)Enabletoolslike“EasyInstall”Pythonpackagemanager(这个很显然)
2)Theyarea“zeroinstallation”formatforpurePythonpackages(putthemonPYTHONPATHorsys.path)(上面说的那个.pth)
3)Theycanincludepackagemetadata(e.g.dependencies)
4)Theyallownamespacepackages(packagesthatcontainotherpackages)tobesplitintoseparatedistributions
5)Theyallowapplicationsorlibrariestospecifytheneededversionofalibrarybeforedoinganimport(e.g.require(“Twisted-Internet>=2.0”))(这个涉及到的是setup里install_requires参数)
6)Theyprovideaframeworkforplug-ins(similartoEclipse’sextensionpoint)
7)EnablesonetodistributeaprojectthatdependsonothersoftwareavailableviaPyPIa.k.a.CheeseShop.(eazy_install或者执行pythonsetup.pyinstall时,会依据install_requires参数自动从http://www.python.org/pypi/上寻找规定的版本,并下载安装好这些依赖的包)

4.eazy_install

EasyInstall/easy_install.py
1)APythonmodulebundledwithsetuptoolsthatletsoneautomaticallybuild,install,andmanagepython
packages
2)Partofthesetuptoolspackage
3)Installsanydistutils-basedpackage
4)CanfindpackagesonPyPI
5)Handlesdependenciesviaargumentstosetup()(e.g.install_requires=[‘foo>=1.4’,’Bar’])

[1]http://docs.python.org/distutils/index.html

[2]http://peak.telecommunity.com/DevCenter/setuptools

[3]http://peak.telecommunity.com/DevCenter/PythonEggs

[4]http://peak.telecommunity.com/DevCenter/EasyInstall

[5]http://www.ibm.com/developerworks/cn/linux/l-cppeak3.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: