什么是setuptools

setuptools是Python distutils增强版的集合,它可以帮助我们更简单的创建和分发Python包,尤其是拥有依赖关系的。用户在使用setuptools创建的包时,并不需要已安装setuptools,只要一个启动模块即可。

功能亮点

  • 利用EasyInstall自动查找、下载、安装、升级依赖包
  • 创建Python Eggs
  • 包含包目录内的数据文件
  • 自动包含包目录内的所有的包,而不用在setup.py中列举
  • 自动包含包内和发布有关的所有相关文件,而不用创建一个MANIFEST.in文件
  • 自动生成经过包装的脚本或Windows执行文件
  • 支持Pyrex,即在可以setup.py中列出.pyx文件,而最终用户无须安装Pyrex
  • 支持上传到PyPI
  • 可以部署开发模式,使项目在sys.path中
  • 用新命令或setup()参数扩展distutils,为多个项目发布/重用扩展
  • 在项目setup()中简单声明entry points,创建可以自动发现扩展的应用和框架
  • 总之,setuptools就是比distutils好用的多,基本满足大型项目的安装和发布

安装setuptools

1) 最简单安装,假定在ubuntu下

# sudo apt-get install python-setuptools

2) 启动脚本安装

wget http://peak.telecommunity.com/dist/ez_setup.py
sudo python ez_setup.py

创建一个简单的包

有了setuptools后,创建一个包基本上是无脑操作

cd /tmp
mkdir demo
cd demo

在demo中创建一个setup.py文件,写入

from setuptools import setup, find_packages
setup(
name = "demo",
version = "0.1",
packages = find_packages(),
)

执行python setup.py bdist_egg即可打包一个test的包了。

demo
|-- build
| `-- bdist.linux-x86_64
|-- demo.egg-info
| |-- dependency_links.txt
| |-- PKG-INFO
| |-- SOURCES.txt
| `-- top_level.txt
|-- dist
| `-- demo-0.1-py2.7.egg
`-- setup.py

在dist中生成的是egg包

file dist/demo-0.1-py2.7.egg
dist/demo-0.1-py2.7.egg: Zip archive data, at least v2.0 to extract 

看一下生成的.egg文件,是个zip包,解开看看先

upzip -l dist/demo-0.1-py2.7.egg

Archive:  dist/demo-0.1-py2.7.egg
Length Date Time Name
--------- ---------- ----- ----
1 2013-06-07 22:03 EGG-INFO/dependency_links.txt
1 2013-06-07 22:03 EGG-INFO/zip-safe
120 2013-06-07 22:03 EGG-INFO/SOURCES.txt
1 2013-06-07 22:03 EGG-INFO/top_level.txt
176 2013-06-07 22:03 EGG-INFO/PKG-INFO
--------- -------
299 5 files

我们可以看到,里面是一系列自动生成的文件。现在可以介绍一下刚刚setup()中的参数了

name 包名
version 版本号
packages 所包含的其他包

要想发布到PyPI中,需要增加别的参数,这个可以参考官方文档中的例子了。

给包增加内容

上面生成的egg中没有实质的内容,显然谁也用不了,现在我们稍微调色一下,增加一点内容。

在demo中执行mkdir demo,再创建一个目录,在这个demo目录中创建一个init.py的文件,表示这个目录是一个包,然后写入:

#!/usr/bin/env python
#-*- coding:utf-8 -*- def test():
print "hello world!" if __name__ == '__main__':
test()

现在的主目录结构为下:

demo
|-- demo
| `-- __init__.py
`-- setup.py
再次执行python setup.py bdist_egg后,再看egg包 Archive: dist/demo-0.1-py2.7.egg
Length Date Time Name
--------- ---------- ----- ----
1 2013-06-07 22:23 EGG-INFO/dependency_links.txt
1 2013-06-07 22:23 EGG-INFO/zip-safe
137 2013-06-07 22:23 EGG-INFO/SOURCES.txt
5 2013-06-07 22:23 EGG-INFO/top_level.txt
176 2013-06-07 22:23 EGG-INFO/PKG-INFO
95 2013-06-07 22:21 demo/__init__.py
338 2013-06-07 22:23 demo/__init__.pyc
--------- -------
753 7 files

这回包内多了demo目录,显然已经有了我们自己的东西了,安装体验一下。

python setup.py install

这个命令会讲我们创建的egg安装到python的dist-packages目录下,我这里的位置在

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

查看一下它的结构:

/usr/local/lib/python2.7/dist-packages/demo-0.1-py2.7.egg
|-- demo
| |-- __init__.py
| `-- __init__.pyc
`-- EGG-INFO
|-- dependency_links.txt
|-- PKG-INFO
|-- SOURCES.txt
|-- top_level.txt
`-- zip-safe

打开python终端或者ipython都行,直接导入我们的包

>>> import demo
>>> demo.test()
hello world!
>>>
# 好了,执行成功!

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'],
}
)

这样,在生成的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的库将这个方式做了封装,更加方便进行应用的扩展。

关注、留言,我们一起学习,您的收藏是我持续更新的动力!

 

===============Talk is cheap, show me the code,bye-bye================

Setuptools 【Python工具包详解】的更多相关文章

  1. Python闭包详解

    Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...

  2. [转] Python Traceback详解

    追莫名其妙的bugs利器-mark- 转自:https://www.jianshu.com/p/a8cb5375171a   Python Traceback详解   刚接触Python的时候,简单的 ...

  3. python 数据类型详解

    python数据类型详解 参考网址:http://www.cnblogs.com/linjiqin/p/3608541.html 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8 ...

  4. Python 递归函数 详解

    Python 递归函数 详解   在函数内调用当前函数本身的函数就是递归函数   下面是一个递归函数的实例: 第一次接触递归函数的人,都会被它调用本身而搞得晕头转向,而且看上面的函数调用,得到的结果会 ...

  5. python线程详解

    #线程状态 #线程同步(锁)#多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题. #threading模块#常用方法:'''threadin ...

  6. python数据类型详解(全面)

    python数据类型详解 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8.字典9.日期 1.字符串1.1.如何在Python中使用字符串a.使用单引号(')用单引号括起来表示字 ...

  7. Python Collections详解

    Python Collections详解 collections模块在内置数据结构(list.tuple.dict.set)的基础上,提供了几个额外的数据结构:ChainMap.Counter.deq ...

  8. python生成器详解

    1. 生成器 利用迭代器(迭代器详解python迭代器详解),我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记 ...

  9. 转 python数据类型详解

    python数据类型详解 目录 1.字符串 2.布尔类型 3.整数 4.浮点数 5.数字 6.列表 7.元组 8.字典 9.日期 1.字符串 1.1.如何在Python中使用字符串 a.使用单引号(' ...

随机推荐

  1. JS实现简单的多选选项的全选反选按钮

    1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <!-- 5 需求: 6 1.写三个按钮: ...

  2. PHP绕过disable_function

    PHP绕过disable_function 常规绕过 exec exec执行command命令,但是不会输出全部结果,而是返回结果的最后一行. 想得到全部的结果,可以使用第二个参数,让其输出到一个数组 ...

  3. Android动画系列之帧动画和补间动画

    原文首发于微信公众号:jzman-blog,欢迎关注交流! Android 提供三种动画:帧动画.补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复 ...

  4. 吴恩达Machine Learning学习笔记(一)

    机器学习的定义 A computer program is said to learn from experience E with respect to some class of tasks T ...

  5. 纯粹极简的react状态管理组件unstated

    简介 unstated是一个极简的状态管理组件 看它的简介:State so simple, it goes without saying 对比 对比redux: 更加灵活(相对的缺点是缺少规则,需要 ...

  6. IDEA 条件断点 进行debug调试

    1. 鼠标左键在要断点的行号点击一下,打个断点 2.鼠标移动到断点处,然后点击一下鼠标右键,之后会弹出: 3.填写条件,可以使用该行中的代码对应的变量作为条件 4.点击Done按钮 至此条件断点设置完 ...

  7. Spring Cloud系列(二):Eureka应用详解

    一.注册中心 1.注册中心演变过程 2.注册中心必备功能 ① 服务的上线 ② 服务的下线 ③ 服务的剔除 ④ 服务的查询 ⑤ 注册中心HA ⑥ 注册中心节点数据同步 ⑦ 服务信息的存储,比如mysql ...

  8. NMOS和PMOS区别

    在很多电路途中会出现NMOS和PMOS管,因为不是中文那么直接,都说管压降之类的,但其实它的导通很重要以及区别,关系到你点亮电子元件> 参考: 1.https://blog.csdn.net/l ...

  9. Arduino 与 SPI 结合使用 以及SPI 深层理解

    本文主要讲解两部分内容,不做任何转发,仅个人学习记录: 一. Arduino 与 SPI 结合使用  : 二. SPI 深层理解 有价值的几个好的参考: 1. 中文版: https://blog.cs ...

  10. 【题解】[USACO08MAR]Land Acquisition G

    Link 题目大意:给定\(n\)个二元组,每次可以选择一组,花费是组内最大的长乘以最大的宽.问消掉所有二元组的最小代价. \(\text{Solution:}\) \(dp\)写的不够啊-- 先挖掘 ...