zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    随笔
    std::condition_variable(复习)
    随笔
    std::vector<std::vector<> >
    staitc_cast,const_cast....
    复制构造函数
    c++ 临时对象
    复制初始化和直接初始化
    随笔
    Fedora 安装oracle11g 之最简洁方式
  • 原文地址:https://www.cnblogs.com/Zzbj/p/10783180.html
Copyright © 2011-2022 走看看