作者:chen_h
1. setuptools 是什么
setuptools 与 disutils
我们通常所知道的 Python 分发工具是 Python distutils, setuptools 可以说是它的增强版,它能帮助我们更好的创建和分发 Python 的包,尤其是具有复杂依赖关系的包。对于开发者来说,能够更好的组织自己项目的分发和发布;对于用户来说,不需要安装 setuptools 也可以使用由它创建的包,只需要一个启动模块即可。
实现这样的的包管理机制主要由两部分构成:
- 一个存储在 Python 官方网站的集中式仓库,名叫 Python Package Index(PyPI)
- 另外就是基于 distutils 开发的 setuptools 包管理系统
它提供的内容包括:
- 用来提供标准元数据字段:诸如作者名、版权类型等信息的骨架
- 一组用来将包中的代码来构建软件安装包的辅助工具
distutils 仅仅适用于包,它无法定义包之间的依赖关系。但是 setuptools 通过添加一个基本的依赖系统以及许多相关功能,弥补了该缺陷。他还提供了自动包查询程序,用来自动获取包之间的依赖关系,并完成这些包的安装,大大降低了安装各种包的难度,使之更加方便。
2. 简单尝试
首先,我们先来定义一个最简单的目录结构,如下:
myapp
├── myapp
│ └── __init__.py
└── setup.py
我们在 __init__.py 文件中写入以下内容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def hello():
return 'This is a test'
在 setup.py 文件中写入以下内容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import setup
setup(name = 'myapp',
version = '1.0',
author = 'chen_h',
author_email = 'naivechen@foxmail.com',
license = 'MIT',
)
之后,我们可以为模块创建一个源码包,运行如下命令:
$ python setup.py sdist
running sdist
running egg_info
creating myapp.egg-info
writing myapp.egg-info/PKG-INFO
writing top-level names to myapp.egg-info/top_level.txt
writing dependency_links to myapp.egg-info/dependency_links.txt
writing manifest file 'myapp.egg-info/SOURCES.txt'
reading manifest file 'myapp.egg-info/SOURCES.txt'
writing manifest file 'myapp.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt
running check
warning: check: missing required meta-data: url
creating myapp-1.0
creating myapp-1.0/myapp.egg-info
making hard links in myapp-1.0...
hard linking setup.py -> myapp-1.0
hard linking myapp.egg-info/PKG-INFO -> myapp-1.0/myapp.egg-info
hard linking myapp.egg-info/SOURCES.txt -> myapp-1.0/myapp.egg-info
hard linking myapp.egg-info/dependency_links.txt -> myapp-1.0/myapp.egg-info
hard linking myapp.egg-info/top_level.txt -> myapp-1.0/myapp.egg-info
Writing myapp-1.0/setup.cfg
creating dist
Creating tar archive
removing 'myapp-1.0' (and everything under it)
现在我们的目录结构如下:
myapp/
├── dist
│ └── myapp-1.0.tar.gz
├── myapp
│ ├── __init__.py
│ └── __init__.pyc
├── myapp.egg-info
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ ├── dependency_links.txt
│ └── top_level.txt
└── setup.py
dist/ 文件夹下面的文件就是我们的源码包,源码包的命名格式为 “应用名 - 版本号 - .tar.gz” 。
之后我们需要去安装这个应用,使用如下命令:
$ python setup.py install
该命令会将当前的 Python 应用安装到当前 Python 环境的 “site-packages” 目录下,这样其他程序就可以像导入标准库一样导入该应用的代码了。
但我们在开发过程中,我们也可以采用开发方式安装,如下命令:
$ python setup.py develop
如果应用在开发过程中会频繁变更,每次安装还需要先把原来的版本卸载,很麻烦。使用 “develop” 开发方式安装的话,应用代码不会真的被拷贝到本地 Python 环境的 “site-packages” 目录下,而是在 “site-packages” 目录里创建一个指向当前应用位置的连接。这样如果当前位置的源码被改动,就会马上反映到 “site-packages” 里。
至此,我们就可以学会如何构建一个最简单的 python 包文件了。
接下来,我们学习一些 setup 别的参数。
3. zip_safe 参数
该参数决定应用是否作为一个 zip 压缩后的 egg 文件安装在当前 Python 环境中,还是作为一个以 .egg 结尾的目录安装在当前环境中。因为有些工具不支持 zip 压缩文件,而且压缩后的包也不方便调试,所以建议将其设为 False ,即 “zip_safe = False” 。
4. 依赖关系和元数据
如果你使用 Python ,很自然就会使用其他人的包。setuptools 给我们提供了很方便的工具来说明依赖关系,而且在安装我们的包的时候回自动安装依赖包。比如我们给刚刚的代码添加一些包。
我们添加一个 mymath.py 文件,如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
def add(a,b):
return np.add(a,b)
之后,我们在 __init__.py 文件中添加包名,如下:
from mymath import add
我们也需要向 setup.py 文件中添加一些内容,如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import setup
setup(name = 'myapp',
version = '1.0',
author = 'chen_h',
author_email = 'naivechen@foxmail.com',
license = 'MIT',
zip_safe = False,
description = 'This is a test for setuptools',
packages = ['myapp'],
install_requires = [
'numpy >= 1.8',
],
)
因为我们是采用 develop 模式来操作的,所以我们不用再次进行安装。直接在终端导入包就好了,如下:
>>> import myapp
>>> myapp.add(2,3)
5
参考:
Python 分发工具初探之 setuptools
python-packaging
Python打包分发工具setuptools简介
Python 分发工具初探之 setuptools