Python深入:setuptools進階


作者:gqtcgq 

來源:CSDN 
原文:https://blog.csdn.net/gqtcgq/article/details/49519685

Setuptools是Python Distutils的加強版,使開發者構建和發布Python包更加容易,特別是當包依賴於其他包時。用setuptools構建和發布的包與用Distutils發布的包是類似的。包的使用者無需安裝setuptools就可以使用該包。如果用戶是從源碼包開始構建,並且沒有安裝過setuptools的話,則只要在你的setup腳本中包含一個bootstrap模塊(ez_setup),用戶構建時就會自動下載並安裝setuptools了。

 

一:基本用例

下面是一個使用setuptools的簡單例子:

 

├── demo
│ └─ myapp
│   └── __init__.py
└── setup.py

 

1.創建一個demo文件夾: mkdir demo

2.新建一個setup.py文件 ,內容如下

from setuptools import setup, find_packages

setup(
    name='HelloWorld',
    version='0.1',
    packages=find_packages(),
    author='ZBJ',
    url='None',
    author_email='None'
)

3.在demo文件夾下再新建一個文件夾:myapp和__init__.py

4.myapp下的__init__.py如下:

def test():
    print("Hello World!")


if __name__ == '__main__':
    test()

5.檢查setup.py是否有錯誤或警告:python setup.py check 

6.執行 python setup.py bdist_egg 即可打包一個test的包了(在dist中生成的是egg包,.egg文件其實是一個zip包)

7.解壓egg包后,安裝該包:python setup.py install

 

上面就是一個最簡單的setup腳本,使用該腳本,就可以產生eggs,上傳PyPI,自動包含setup.py所在目錄中的所有包等。

當然,上面的腳本過於簡單,下面是一個稍微復雜的例子:

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    scripts = ['say_hello.py'],

    # Project uses reStructuredText, so ensure that the docutils get
    # installed or upgraded on the target machine
    install_requires = ['docutils>=0.3'],

    package_data = {
        # If any package contains *.txt or *.rst files, include them:
        '': ['*.txt', '*.rst'],
        # And include any *.msg files found in the 'hello' package, too:
        'hello': ['*.msg'],
    },

    # metadata for upload to PyPI
    author = "Me",
    author_email = "me@example.com",
    description = "This is an Example Package",
    license = "PSF",
    keywords = "hello world example examples",
    url = "http://example.com/HelloWorld/",   # project home page, if any
    # could also include long_description, download_url, classifiers, etc.
)

 

上面的腳本包含了更多的信息,比如依賴、數據文件、腳本等等,接下來的幾節會詳細解釋。

 

二:find_packages

對於簡單的工程,使用setup函數的packages參數一一列出安裝的包到就足夠了。但是對於大型工程來說,這卻有點麻煩,因此就有了setuptools.find_package()函數。

find_packages的參數有:一個源碼目錄,一個include包名列表,一個exclude包名列表。如果這些參數被忽略,則源碼目錄默認是setup.py腳本所在目錄。該函數返回一個列表,可以賦值給packages參數。

有些工程可能會使用src或者lib目錄作為源碼樹的子目錄,因此這些工程中,需要使用”src”或者”lib”作為find_packages()的第一個參數,當然,這種情況下還需要設置package_dir = {'':'lib'},否則的話會報錯,比如setup腳本如下:

 

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    package_dir = {'':'lib'},
    packages = find_packages('lib'),
)

 

源碼樹如下:

 

lib/
    foo.py
    heheinit.py
    bar/
        __init__.py
        bar.py

 

最終生成的文件是:

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/dependency_links.txt

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/PKG-INFO

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/SOURCES.txt

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/top_level.txt

/usr/local/lib/python2.7/dist-packages/bar/bar.py

/usr/local/lib/python2.7/dist-packages/bar/bar.pyc

/usr/local/lib/python2.7/dist-packages/bar/__init__.py

/usr/local/lib/python2.7/dist-packages/bar/__init__.pyc

 

如果沒有package_dir = {'':'lib'}的話,則會報錯:

 

error: package directory 'bar' does not exist

這是因為執行函數find_packages('lib'),返回的結果是['bar'],沒有package_dir = {'':'lib'}的話,則在setup.py所在目錄尋找包bar,自然是找不到的了。

 

>>> import setuptools
>>> setuptools.find_packages('lib')
['bar']

 

 

 

find_packages()函數遍歷目標目錄,根據include參數進行過濾,尋找Python包。對於Python3.2以及之前的版本,只有包含__init__.py文件的目錄才會被當做包。最后,對得到的結果進行過濾,去掉匹配exclude參數的包。

include和exclude參數是包名的列表,包名中的’.’表示父子關系。比如,如果源碼樹如下:

 

lib/
    foo.py
    __init__.py
    bar/
        __init__.py
        bar.py

 

則find_packages(exclude=["lib"])(或packages = find_packages(include=["lib"])),只是排除(或包含)lib包,但是卻不會排除(或包含lib.bar)包。

 

三:entry points

entry points是發布模塊“宣傳”Python對象(比如函數、類)的一種方法,這些Python對象可以被其他發布模塊使用。一些可擴展的應用和框架可以通過特定的名字找到entry points,也可以通過發布模塊的名字來找到,找到之后即可加載使用這些對象了。

 

entry points要屬於某個entry points組,組其實就是一個命名空間。在同一個entry point組內不能有相同的entry point。

 

entry points通過setup函數的entry_points參數來表示,這樣安裝發布包之后,發布包的元數據中就會包含entry points的信息。entry points可以實現動態發現和執行插件,自動生成可執行腳本、生成可執行的egg文件等功能。

setup函數的entry_points參數,可以是INI形式的字符串,也可以是一個字典,字典的key是entry point group的名字,value是定義entry point的字符串或者列表。

一個entry point就是”name = value”形式的字符串,其中的value就是某個模塊中對象的名字。另外,在”name = value”中還可以包含一個列表,表示該entry point需要用到的”extras”,當調用應用或者框架動態加載一個entry point的時候,”extras”表示的依賴包就會傳遞給pkg_resources.require()函數,因此如果依賴包沒有安裝的話就會打印出相應的錯誤信息。

比如entry_points可以這樣寫:

 

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

setup(
    ...
    entry_points = {'blogtool.parsers': '.rst = some_module:SomeClass[reST]'}
    extras_require = dict(reST = "Docutils>=0.3.5")
    ...
)

setup(
    ...
    entry_points = {'blogtool.parsers': ['.rst = some_module:a_func[reST]']}
    extras_require = dict(reST = "Docutils>=0.3.5")
    ...
)

 

 

1:動態發現服務和插件

setuptools支持向可擴展應用和框架中插入自己的代碼。通過在自己的模塊發布中注冊”entry points”,就可以被應用或框架引用。

下面以向一個內容管理系統(content management system,CMS)中添加新類型的內容為例,描述如何使用entry points創建插件。

要安裝的插件的源碼樹如下:

 

lib/
    foo.py
    __init__.py
    bar/
        __init__.py
        bar.py

 

 

為了定義插件,使用自定義的”cms.plugin”作為”entry point group”名。setup.py腳本內容如下:

 

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    entry_points = {
        'cms.plugin': [
            'foofun = lib.foo:foofun',
            'barfun = lib.bar.bar:barfun'
        ]
    }
)

 

注意,entry points引用的對象不一定非得是函數,它可以是任意的Python對象,而且entry point的名字也不一定非得是entry points引用的對象名字。

 

定義好setup.py之后,就可以通過python setup.py install安裝該包,生成的文件是:

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

/usr/local/lib/python2.7/dist-packages/easy-install.pth

其中的HelloWorld-0.1-py2.7.egg是個標准的ZIP文件,解壓后生成:

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/dependency_links.txt

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/entry_points.txt

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/PKG-INFO

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/SOURCES.txt

/usr/local/lib/python2.7/dist-packages/HelloWorld-0.1-py2.7.egg-info/top_level.txt

/usr/local/lib/python2.7/dist-packages/lib/__init__.py

/usr/local/lib/python2.7/dist-packages/lib/__init__.pyc

/usr/local/lib/python2.7/dist-packages/lib/foo.py

/usr/local/lib/python2.7/dist-packages/lib/foo.pyc

/usr/local/lib/python2.7/dist-packages/lib/bar/__init__.py

/usr/local/lib/python2.7/dist-packages/lib/bar/__init__.pyc

/usr/local/lib/python2.7/dist-packages/lib/bar/bar.py

/usr/local/lib/python2.7/dist-packages/lib/bar/bar.pyc

 

插件安裝好之后,就可以在CMS中編寫加載插件的代碼了。既可以通過發布的名字和版本號找到插件,也可以通過entry point group和entry point的名字,一般使用后者,比如動態加載插件的代碼如下:

 

from pkg_resources import iter_entry_points
for entry_point in iter_entry_points(group='cms.plugin', name=None):
    print(entry_point)
    fun = entry_point.load()
    fun()

 

運行該腳本,結果如下:

 

barfun = lib.bar.bar:barfun
hello, this is barfun
foofun = lib.foo:foofun
hello, this is foofun

也可以通過iter_entry_points中的name參數,加載特定的entry_points

 

 

2:自動創建腳本

setuptools能夠自動生成可執行腳本,在Windows平台上他甚至能創建一個exe文件。這就是通過setup.py腳本中的”entry points”實現的,它指明了生成的腳本需要引入並運行的函數。

比如,源碼樹如下:

 

lib/
    foo.py
    __init__.py
    bar/
        __init__.py
        bar.py

其中的foo.py內容如下:

 

 

def foofun():
    print 'hehe, this is foofun'

 

bar.py內容如下:

 

def barfun():
    print 'hehe, this is barfun'


要創建兩個控制台腳本foohehe和barhehe,setup腳本內容如下:

 

 

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    entry_points = {
        'console_scripts': [
            'foohehe = lib.foo:foofun',
            'barhehe = lib.bar.bar:barfun',
        ]
    }
)

注意要創建控制台腳本,只能使用“console_scripts”作為entry point group名,要創建GUI腳本,只能使用“gui_scripts”作為entry point group名。否則就不會生成相應的腳本或者exe文件。

 

 

安裝之后,生成的文件是:

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

/usr/local/lib/python2.7/dist-packages/easy-install.pth

/usr/local/bin/foohehe

/usr/local/bin/barhehe

其中的HelloWorld-0.1-py2.7.egg是個標准的ZIP文件,解壓后生成的文件與上例相同。

 

其中的foohehe和barhehe是兩個可執行python腳本,foohehe內容如下:

 

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

if __name__ == '__main__':
    sys.exit(
        load_entry_point('HelloWorld==0.1', 'console_scripts', 'foohehe')()
    )

 

barhehe內容如下:

 

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

if __name__ == '__main__':
    sys.exit(
        load_entry_point('HelloWorld==0.1', 'console_scripts', 'barhehe')()
    )

 

運行foohehe和barhehe都可以得到正確的打印結果。如果在Windows上安裝,則會創建相應的exe文件和py文件。exe文件將會使用Python運行py文件。

 

pkg_resources還提供了很多有關entry points的API,具體可以參閱:https://pythonhosted.org/setuptools/pkg_resources.html#convenience-api

 

 

3:生成可執行的egg文件

還可以通過entry point創建直接可執行的egg文件。比如,還是上面的例子,包的源碼樹和內容都沒有變,只不過setup.py的內容是:

 

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    entry_points = {
        'setuptools.installation': [
            'eggsecutable = lib.foo:foofun',
        ]
    }
)

 

安裝之后,生成的文件是:

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

/usr/local/lib/python2.7/dist-packages/easy-install.pth

 

其中的HelloWorld-0.1-py2.7.egg也是個ZIP壓縮文件,解壓后的文件與上例相同,不同的地方在於,HelloWorld-0.1-py2.7.egg文件除了包含壓縮數據之外,還包含了一個shell腳本。ZIP文件支持在壓縮數據之外附加額外的數據:https://en.wikipedia.org/wiki/Zip_(file_format)#Combination_with_other_file_formats)

 

用UltraEdit查看HelloWorld-0.1-py2.7.egg的內容,發現它在壓縮數據文件頭(0x504B0304)之前,包含了下面的內容:

 

#!/bin/sh
if [ `basename $0` = "HelloWorld-0.1-py2.7.egg" ]
then exec python2.7 -c "import sys, os; sys.path.insert(0, os.path.abspath('$0')); from lib.foo import foofun; sys.exit(foofun())" "$@"
else
  echo $0 is not the correct name for this egg file.
  echo Please rename it back to HelloWorld-0.1-py2.7.egg and try again.
  exec false
fi

 

這是一段shell腳本,因此,將該egg文件使用/bin/bash執行,它會執行lib.foo:foofun函數:

 

# /bin/bash HelloWorld-0.1-py2.7.egg 
hello, this is foofun

 

 

注意使用entry_points創建可執行的egg文件時,其中的”setuptools.installation”和”eggsecutable”是固定寫法,不可更改,否則不會起作用。

從上面的腳本內容可見,shell腳本對文件名進行了檢查,因此要想直接運行該egg文件,不能改名,不能使用符號鏈接,否則會執行失敗。

這種特性主要是為了支持ez_setup,也就是在非Windows上安裝setuptools本身,當然也有可能在其他項目中會使用到。

 

四:依賴

setuptools支持在安裝發布包時順帶安裝它的依賴包,且會在Python Eggs中包含依賴的信息,這樣像easyinstall這樣的包管理工具就可以使用這些信息了。

setuptools和pkg_resources使用一種常見的語法來說明依賴。首先是一個發布包的PyPI名字,后跟一個可選的列表,列表中包含了額外的信息,之后可選的跟一系列逗號分隔的版本說明。版本說明就是由符號<, >, <=, >=, == 或 != 跟一個版本號。

一個項目的版本說明在內部會以升序的版本號進行排序,用來生成一個可接受的版本范圍,並且會將相鄰的冗余條件進行結合(比如”>1,>2”會變為”>1”,”<2,<3”會變為”<3”)。”!=”表示的版本會在范圍內被刪除。生成版本范圍之后,就會檢查項目的版本號是否在該范圍內。注意,如果提供的版本信息有沖突(比如 “<2,>=2” 或“==2,!=2”),這是無意義的,並且會產生奇怪的結果。

下面是一些說明依賴的例子:

 

docutils >= 0.3

BazSpam ==1.1, ==1.2, ==1.3, ==1.4, ==1.5, ==1.6, ==1.7  

PEAK[FastCGI, reST]>=0.5a4

setuptools==0.5a7

 

 

1:基本用法

當安裝你的發布包的時候,如果setup.py中指明了本包的依賴,則不管使用easyinstall,還是setup.py install,還是setup.py develop,所有未安裝的依賴,都會通過PyPI定位,下載,構建並且安裝,安裝好的發布包的Egg中,還會生成一個包含依賴關系的元數據文件。

 

使用setup函數的install_requires參數來指明依賴,該參數包含說明依賴的字符串或列表,如果在一個字符串中包含了多個依賴,則每個依賴必須獨占一行。

比如下面的setup.py:

 

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    install_requires = "foobar",
)

 

說明該HelloWorld發布包依賴於foobar模塊,用python setuo.py install安裝時,如果還沒有安裝過foobar,則會在PyPI以及其他模塊庫中尋找foobar模塊,如果找不到則會報錯:

 

…
Processing dependencies for HelloWorld==0.1
Searching for foobar
Reading https://pypi.python.org/simple/foobar/
Reading http://ziade.org
No local packages or download links found for foobar
error: Could not find suitable distribution for Requirement.parse('foobar')

 

 

如果已經安裝好了foobar包的話,則會打印:

 

…
Processing dependencies for HelloWorld==0.1
Searching for foobar==0.1
Best match: foobar 0.1
Processing foobar-0.1-py2.7.egg
foobar 0.1 is already the active version in easy-install.pth

Using /root/.local/lib/python2.7/site-packages/foobar-0.1-py2.7.egg
Finished processing dependencies for HelloWorld==0.1

 

 

如果依賴的模塊沒有在PyPI中注冊,則可以通過setup()的dependency_links參數,提供一個下載該模塊的URL。dependency_links選項是一個包含URL字符串的列表,URL可以是直接可下載文件的URL,或者是一個包含下載鏈接的web頁面,還可以是模塊庫的URL。比如:

 

setup(
    ...
    dependency_links = [
        "http://peak.telecommunity.com/snapshots/"
    ],
)

 

 

2:動態依賴

如果發布包中有腳本的話,則該腳本在運行時會驗證依賴是否滿足,並將相應版本的依賴包的路徑添加到sys.path中。比如下面自動生成腳本的setup.py:

 

from setuptools import setup, find_packages
setup(
    name = "Project-A",
    version = "0.1",
    packages = find_packages(),
    install_requires = "foobar",
    entry_points = {
        'console_scripts': [
            'foofun = lib.foo:foofun',
            'barfun = lib.bar.bar:barfun'
        ]
    }
)

 

安裝Project-A的時候,就會順帶安裝foobar模塊,如果安裝都成功了,就會生成腳本/usr/bin/foofun和/usr/bin/barfun。

在運行腳本foofun和barfun時就會查看依賴是否滿足。比如安裝成功后,將foobar的egg文件刪除,則運行foofun或者barfun的時候就會報錯:

 

Traceback (most recent call last):
  File "./barfun", line 5, in <module>
    from pkg_resources import load_entry_point
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 3084, in <module>
    @_call_aside
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 3070, in _call_aside
    f(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 3097, in _initialize_master_working_set
    working_set = WorkingSet._build_master()
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 651, in _build_master
    ws.require(__requires__)
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 952, in require
    needed = self.resolve(parse_requirements(requirements))
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 839, in resolve
    raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'foobar' distribution was not found and is required by Project-A

 

 

3:”extras”

還可以指定非強制性的依賴,比如某個發布包A,若在已經安裝了ReportLab 的情況下,就可選的支持PDF輸出,這種可選的特征叫做”extras”,setuptools允許定義”extras”的依賴。”extras”的依賴不會自動安裝,除非其他發布包B的setup.py中用install_requires明確的指定依賴發布包A的”extras”特性。

 

使用setup函數的extras_require參數來說明” extras”, extras_require是一個字典,key是”extra”的名字,value就是描述依賴的字符串或者字符串列表。比如下面的Project-A就提供了可選的PDF支持:

 

setup(
    name="Project-A",
    ...
    extras_require = {
        'PDF':  ["ReportLab>=1.2", "RXP"]
    }
)

在安裝Project-A的時候,”extras”的依賴ReportLab不會自動安裝,除非其他的發布包的setup.py中的明確的指明,比如:

 

 

setup(
    name="Project-B",
    install_requires = ["Project-A[PDF]"],
    ...
)

 

這樣在安裝Project-B時,如果沒有安裝過Project-A,就會在PyPI中尋找項目Project-A和ReportLab。如果項目A已經安裝過,但ReportLab未安裝,則會去尋找ReportLab:

 

…
Processing dependencies for Project-B
Searching for ReportLab>=1.2
Reading https://pypi.python.org/simple/ReportLab/
…

注意,如果Project-A的PDF特性的依賴改變了,比如變成了tinyobj,則需要重新安裝一遍Project-A,否則安裝Project-B時,還是會尋找ReportLab。

 

 

注意,如果某個extra的特性不依賴於其他模塊,則可以這樣寫:

 

setup(
    name="Project-A",
    ...
    extras_require = {
        'PDF':  []
    }
)

 

 

extras可以用entry_point來指定動態依賴。比如下面自動生成腳本的例子:

 

setup(
    name="Project-A",
    ...
    entry_points = {
        'console_scripts': [
            'rst2pdf = project_a.tools.pdfgen [PDF]',
            'rst2html = project_a.tools.htmlgen',
        ],
},
    extras_require = {
        'PDF':  []
    }
)

這種情況,只有在運行rst2pdf腳本的時候,才會嘗試解決PDF依賴,如果無法找到依賴,則會報錯。運行rst2html就不需要依賴。

 

 

運行注冊的插件時,也是動態檢查依賴的例子,比如:

 

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    entry_points = {
        'cms.plugin': [
            'foofun = lib.foo:foofun[pdf]',
            'barfun = lib.bar.bar:barfun'
        ]
    },
    extras_require = dict(pdf = "foobar")
)


動態加載插件的代碼如下:

 

 

from pkg_resources import iter_entry_points
for entry_point in iter_entry_points(group='cms.plugin', name='foofun'):
    print(entry_point)
    fun = entry_point.load()
    fun()


如果沒有安裝foobar模塊,則運行上面的腳本就會報錯:

 

 

# python testplugin.py 
foofun = lib.foo:foofun [pdf]
Traceback (most recent call last):
  File "testplugin.py", line 7, in <module>
    fun = entry_point.load()
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2354, in load
    self.require(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2371, in require
    items = working_set.resolve(reqs, env, installer)
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 839, in resolve
    raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'foobar' distribution was not found and is required by the application

 

 

五:easy_install

easy_install是setuptools中的一個模塊,使用它可以自動從網上下載、構建、安裝和管理Python發布包。安裝完setuptools之后,easy_install就會自動安裝到/usr/bin中。

使用easy_install安裝包,只需要提供文件名或者一個URL即可。如果僅提供了文件名,則該工具會在PyPI中搜索該包的最新版本,然后自動的下載、構建並且安裝。比如:

 

easy_install SQLObject

 

 

也可以指定其他下載站點的URL,比如:

 

easy_install -f http://pythonpaste.org/package_index.html SQLObject

 

或者是:

 

easy_install http://example.com/path/to/MyPackage-1.2.3.tgz

 

 

或者,可以安裝本地的egg文件,比如:

 

easy_install /my_downloads/OtherPackage-3.2.1-py2.3.egg

 

 

可以將一個已經安裝過的包更新到PyPI的最新版本:

 

easy_install --upgrade PyProtocols

 

 

如果是想卸載某個發布包,則需要先運行:

 

easy_install -m PackageName

這就能保證Python不會繼續搜索你要卸載的包了。執行該命令之后,就可以安全的刪除.egg文件或目錄,以及相應的可執行腳本。

 

更多關於easy_install的信息,參閱:https://setuptools.pypa.io/en/latest/easy_install.html

 

六:版本號

版本號的作用,就是能使setuptools和easyinstall可以分辨出包的新舊關系。

 

版本號是由一系列的發布號、prerelease標簽、postrelease標簽交替組成的。

發布號是一系列數字和點號(‘.’)穿插組成。比如2.4、0.5等。這些發布號被當做數字來看待,所以2.1和2.1.0是同一版本號的不同寫法,表示的是發布號2之后的第一個子發布。但是像2.10表示的是發布號2之后的第10個子發布,所以2.10要比2.1.0更新。注意在數字之前緊挨着的0是會被忽略的,所以2.01等同於2.1,但是不同於2.0.1。

prerelease標簽是按照字母順序在”final”之前的一系列字母(單詞),比如alpha,beta,a,c,dev等等。發布號和pre-release標簽之間可以為空,也可以是’.’或’-’。所以2.4c1、2.4.c1和2.4-c1,它們都是等同的,都表示版本2.4的1號候選(candidate )版本。另外,有三個特殊的prerelease標簽被看做與字母’c’(candidate)一樣:pre、preview和rc。所以版本號2.4rc1,2.4pre1和2.4preview1,在setuptools看來它們和2.4c1是一樣的。

帶有prerelease標簽的版本號要比不帶該標簽的相同版本號要舊,所以2.4a1, 2.4b1以及2.4c1都比2.4更舊。

 

相應的,postrelease標簽是按照字母順序在”final”之后的一系列字母(單詞),或者可以是單獨的一個’-’。postrelease標簽經常被用來分隔發布號和補丁號、端口號、構件號、修訂號以及時間戳等。比如2.4-r1263表示繼2.4之后發布的第1263號修訂版本,或者可以用2.4-20051127表示一個后續發布的時間戳。

帶有postrelease標簽的版本號要比不帶該標簽的相同版本號更新,所以2.4-1, 2.4p13都比2.4更新,但是要比2.4.1更舊(2.4.1的發布號更高)。

 

注意在prerelease標簽或postrelease標簽之后,也可以跟另外的發布號,然后發布號之后又可以跟prerelease或postrelease標簽。比如0.6a9.dev-r41475,因dev是prerelease標簽,所以該版本要比0.6a9要舊,-r41475是postrelease標簽,所以該版本要比0.6a9.dev更新。

注意,不要把兩個prerelease標簽寫在一起,它們之間要有點號、數字或者’-‘分隔。比如1.9adev與1.9a.dev是不同的。1.9a0dev、1.9a.dev、1.9a0dev和1.9.a.dev是相同的。

 

可以使用函數pkg_resources.parse_version()來測試不同版本號之間的關系:

 

>>> from pkg_resources import parse_version
>>> parse_version('1.9.a.dev') == parse_version('1.9a0dev')
True
>>> parse_version('2.1-rc2') < parse_version('2.1')
True
>>> parse_version('0.6a9dev-r41475') < parse_version('0.6a9')
True

 

 

七:其他

其他有關Setuptools的信息,可查閱官方文檔:https://setuptools.pypa.io/en/latest/setuptools.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM