setuptools 是什么
https://github.com/pypa/setuptools 下载源码, 解压后, 在python3环境下, 执行 python setup.py install,会自动安装setuptools
可以新建demo, 主要是要新建一个seup.py, 里面的内容参见下面。
执行 将这个egg包copy到 python安装目录 C:\Programs\Python\Python35\Lib\site-packages下, 就能正常 import 了
看下 http://blog.youkuaiyun.com/gqtcgq/article/details/49519685
setup( name = "HelloWorld", # 包名 version = "0.1", # 版本信息 packages = ['project_file'], # 要打包的项目文件夹 include_package_data=True, # 自动打包文件夹内所有数据 zip_safe=True, # 设定项目包为安全,不用每次都检测其安全性 install_requires = [ # 安装依赖的其他包 'docutils>=0.3', 'requests', ], # 设置程序的入口为hello # 安装后,命令行执行hello相当于调用hello.py中的main方法 entry_points={ 'console_scripts':[ 'hello = project_file.hello:main' ] }, # 如果要上传到PyPI,则添加以下信息 # author = "Me", # author_email = "me@example.com", # description = "This is an Example Package", # license = "MIT", # keywords = "hello world example examples", # url = "http://example.com/HelloWorld/", )
要包含文件夹, 首先得是一个包, 成为包后可以通过下面包含包内其他后缀的文件setup(
name = "demo",
version = "0.1",
#package_dir = {'':'demo'},
packages = find_packages(),
include_package_data=True,
package_data = {
# If any package contains *.txt or *.rst files, include them:
'': ['*.*'],
},
)
'''
package_data = {
# If any package contains *.txt or *.rst files, include them:
'': ['*.txt', '*.rst','*.exe'],
# And include any *.msg files found in the 'hello' package, too:
'demo': ['*.*','*.txt','*.exe'],
},
'''
setuptools 与 disutils
我们通常所知道的 Python 分发工具是 Python disutils, setuptools 可以说是它的增强版,它能帮助我们更好的创建和分发 Python 的包,尤其是具有复杂依赖关系的包。对于开发者来说,能够更好的组织自己项目的分发和发布;对于用户来说,不需要安装 setuputils 也可以使用由它创建的包,只需要一个启动模块即可。
实现这样的的包管理机制主要由两部分构成:
- 一个存储在 Python 官方网站的集中式仓库,名叫 Python Package Index(PyPI)
- 另外就是基于 disutils 开发的 setuptools 包管理系统
它提供的内容包括:
- 用来提供标准元数据字段:诸如作者名、版权类型等信息的骨架
- 一组用来将包中的代码来构建软件安装包的辅助工具
disutils 仅仅适用于包,它无法定义包之间的依赖关系。但是 setuptools 通过添加一个基本的依赖系统以及许多相关功能,弥补了该缺陷。他还提供了自动包查询程序,用来自动获取包之间的依赖关系,并完成这些包的安装,大大降低了安装各种包的难度,使之更加方便。
相关功能
- 利用 EasyInstall 自动查找、下载、安装升级依赖包
- 能够创建 Python Eggs、
- 包含目录中的数据文件和包,不需要在
setup()函数中一一列举出来 - 自动包含包内和发布有关的所有相关文件,而不用创建一个
MANIFEST.in文件 - 自动生成经过包装的脚本
- 支持Pyrex,即在可以
setup.py中列出.pyx文件,而最终用户无须安装Pyrex - 支持上传到 PyPI
- 可以部署开发模式,使项目在sys.path中
- 用新命令或
setup()参数扩展distutils,为多个项目发布/重用扩展 - 在项目的
setup()中简单声明entry points,创建可以自动发现扩展的应用和框架
0x01 安装 setuptools
**Ubuntu:
- 1
- 1
Mac:
安装 wget:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
安装 setuputils:
- 1
- 2
- 1
- 2
0x02 创建一个简单的包
创建一个空的包
新建一个 demo 目录
- 1
- 2
- 1
- 2
在目录下新建 setup.py 文件
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
将该项目打包
- 1
- 1
这时我们查看该项目目录:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
我们看到在 dist 目录中的就是生成的 egg 包,将其解压:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
以上的程序是最简单的一个 setup.py 程序,如果想要发布到 PyPI 就需要参考官方给出的示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
给包中添加内容
我们上边生成的 egg 是一个空的,没有实际的内容,现在我们来添加一些内容:
在项目目录新建一个目录:
- 1
- 2
- 1
- 2
* 新建 __init__.py,加入如下代码:*
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
需要将scripts = ['say_hello.py'], 这行删除掉, 因为暂时还没有say_hello.py文件,
如果将该包放到了文件夹src下面,一般会将源码放在文件夹src下面, 需要将参数改成
packages=find_packages('src'),
package_dir = {'':'src'}
再次生成 egg 包:
- 1
- 1
查看 egg 包内容:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
我们看到其中已经多了 test 目录和 __init__.py,然后我们就可以尝试安装一下我们自己的包:
- 1
- 1
然后该包就会安装到 Python 的 site-packages 目录下,在我的电脑上为 /Library/Python/2.7/site-packages/demo1-0.1-py2.7.egg
这时我们可以在 Python 终端测试我们的包:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
我们看到我们编写的包已经成功运行!
0x02 总结
这篇文章主要介绍了一下 setuptools 是什么,以及它的功能和特点,并且介绍了如何使用它来创建和安装使用自己的包,这篇文章仅仅讲了最基本的功能和用法,一些对于进阶的用法会在下篇文章中进行介绍。
4.setuptools进阶
在上例中,在前两例中,我们基本都使用setup()的默认参数,这只能写一些简单的egg。一旦我们的project逐渐变大以后,维护起来就有点复杂了,下面是setup()的其他参数,我们可以学习一下
使用find_packages()
对于简单工程来说,手动增加packages参数很容易,刚刚我们用到了这个函数,它默认在和setup.py同一目录下搜索各个含有__init__.py的包。其实我们可以将包统一放在一个src目录中,另外,这个包内可能还有aaa.txt文件和data数据文件夹。
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'],
}
)
(The empty string stands for the root package.)
package_dir = {'':'src'},
这样,在生成的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是用来支持动态发现服务和插件的,也用来支持自动生成脚本。这个还是看例子比较好理解:
setup(
entry_points = {
'console_scripts': [
'foo = demo:test',
'bar = demo:test',
],
'gui_scripts': [
'baz = demo:test',
]
}
)
修改setup.py增加以上内容以后,再次安装这个egg,可以发现在安装信息里头多了两行代码(Linux下):
Installing foo script to /usr/local/bin
Installing bar script to /usr/local/bin
查看/usr/local/bin/foo内容
#!/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')()
)
这个内容其实显示的意思是,foo将执行console_scripts中定义的foo所代表的函数。执行foo,发现打出了hello world!,和预期结果一样。
使用Eggsecutable Scripts
从字面上来理解这个词,Eggsecutable是Eggs和executable合成词,翻译过来就是另eggs可执行。也就是说定义好一个参数以后,可以另你生成的.egg文件可以被直接执行,貌似Java的.jar也有这机制?不很清楚,下面是使用方法:
setup(
# other arguments here...
entry_points = {
'setuptools.installation': [
'eggsecutable = demo:test',
]
}
)
这么写意味着在执行python *.egg时,会执行我的test()函数,在文档中说需要将.egg放到PATH路径中。
包含数据文件
在3中我们已经列举了如何包含数据文件,其实setuptools提供的不只这么一种方法,下面是另外两种
1)包含所有包内文件
这种方法中包内所有文件指的是受版本控制(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中提到的包含方法
可扩展的框架和应用
setuptools可以帮助你将应用变成插件模式,供别的应用使用。官网举例是一个帮助博客更改输出类型的插件,一个博客可能想要输出不同类型的文章,但是总自己写输出格式化代码太繁琐,可以借助一个已经写好的应用,在编写博客程序的时候动态调用其中的代码。
通过entry_points可以定义一系列接口,供别的应用或者自己调用,例如:
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中的函数,以名字为blogtool.parsers的借口共享给别的应用。
别的应用使用的方法是通过pkg_resources.require()来导入这些模块。
另外,一个名叫stevedore的库将这个方式做了封装,更加方便进行应用的扩展。
5. 以后增加
本文介绍Python包管理工具setuptools的基础使用方法及高级特性,包括安装、创建包、使用entry_points等。
632

被折叠的 条评论
为什么被折叠?



