摘要本文会介绍 python 的标准打包及分发工具 setuptools。会介绍 setup.py 文件的格式,以及四种安装的方式。
简介
作为 python 标准的打包及分发工具,setuptools 可以说相当地简单易用。它会随着 python 一起安装在你的机器上。你只需写一个简短的 setup.py 安装文件,就可以将你的 python 应用打包。
参考资料
- python打包分发工具setuptools简介,这是一个比较简洁的教程;
- python的构建工具setup.py,这里对 setup.py 中的设置进行了详细的介绍;
- setuptools详解,这个会对
find_package
和entry_points
说明比较详细;
setup.py 文件编写
这一部分我们直接来看一个 setup.py
文件的例子,然后对这个文件做出详细的解释:
- from __future__ import absolute_import
- from __future__ import division
- from __future__ import print_function
- from setuptools import setup, find_packages
- import os
- here = os.path.abspath(os.path.dirname(__file__)) # 将 setup.py 放在项目的根目录
- setup(
- name = "test",
- version = "1.0",
- keywords = ("test", "xxx"),
- description = "eds sdk",
- long_description = "eds sdk for python",
- license = "apache license, version 2.0",
- url = "http://test.com",
- author = "test",
- author_email = "[email protected]",
- packages = find_packages(),
- include_package_data = true,
- install_requires=[i.strip() for i in open(os.path.join(os.path.dirname(__file__), 'requirements.txt')).readlines() if i.strip()],
- entry_points = {
- 'console_scripts': [
- 'test = test.help:main'
- ]
- }
- )
下面是 setup.py
中各个参数的解释:
- 基础描述信息:
- name 包名称(起一个响亮的名字)
- version (-v) 包版本
- author 程序的作者
- author_email 程序的作者的邮箱地址
- maintainer 维护者
- maintainer_email 维护者的邮箱地址
- url 程序的ag真人试玩娱乐官网地址
- license 程序的授权信息
- description 程序的简单描述
- long_description 程序的详细描述
- platforms 程序适用的软件平台列表
- keywords 程序的关键字列表
- classifiers 程序的所属分类列表
- 包的进阶信息:
- packages 需要处理的包目录(包含__init__.py的文件夹),这里通常使用 find_packages(),它默认在和setup.py同一目录下搜索各个含有 __init__.py的包。
- install_requires = ["requests"] 需要安装的依赖包。我们可以首先生成 requirements.txt 文件,接着使用生成的文件生成需要的参数。关于生成 requirements.txt 文件,可以参考python自动生成requirements.txt文件。
- include_package_data,引入非 python 文件。默认情况下只会对 python 源码进行打包,但是如果我们想要将其他静态文件,例如 css 文件,或是 qt 的一些 ui 文件打包进去,就需要使用这个参数。后面会有详细的介绍。
- 制作命令行工具:
- entry_points 动态发现服务和插件,可以用来制作命令行工具。也就是我们可以通过一些简单的命令,来运行 python 项目中的指定文件或是函数。下面会详细进行介绍。
packages 的说明(自动搜索 python 包)
我们指定 packages
后会自动将指定的 package
下的源代码进行打包。但是有的时候会有很多 subpackage
,这个时候 setuptools
提供了 find_packages
来找到所有的 subpackages
。下面图展示了大概的效果:
include_package_data(引入非 python 文件)
默认情况下我们的打包只会对源码进行打包。如果我们还想将其他非 python 文件也打包,比如静态文件(js,css,图片),应该怎么做呢?这时我们要在项目目录下添加一个 manifest.in
文件夹。假设我们把所有静态文件都放在 static 子目录下,现在的目录结构如下所示:
- setup-demo/
- ├ setup.py # 安装文件
- ├ manifest.in # 清单文件
- └ myapp/ # 源代码
- ├ static/ # 静态文件目录
- ├ __init__.py
- ...
我们首先在清单文件 manifest.in
中,列出想要在包内引入的目录路径:
- include myapp/static *.css # 只包含 static 文件夹中的 css 文件
- recursive-include myapp/xxx * # 递归包含
这里有一点需要注意,最后的文件夹不要加斜杠,也就是不能写成 myapp/static/
这种形式,一定是要写成 myapp/static
这种形式。
上面recursive-include
表明包含子目录。别急,还有一件事要做,就是在 setup.py 中将 include_package_data
参数设为 true:
- #coding:utf8
- from setuptools import setup
- setup(
- name='myapp', # 应用名
- version='1.0', # 版本号
- packages=['myapp'], # 包括在安装包内的python包
- include_package_data=true # 启用清单文件manifest.in
- )
之后再次打包或者安装,myapp/static
目录下的所有文件都会被包含在内。如果你想排除一部分文件,可以在 setup.py
中使用exclude_package_date
参数,比如:
- setup(
- ...
- include_package_data=true, # 启用清单文件manifest.in
- exclude_package_date={'':['.gitignore']}
- )
上面的代码会将所有 .gitignore
文件排除在包外。如果上述 exclude_package_date
对象属性不为空,比如{'myapp':['.gitignore']}
,就表明只排除 myapp
包下的所有 .gitignore
文件。
install_requires 的说明(自动安装依赖)
这个参数是在 setup.py 文件中指定依赖,然后在使用 setuptools 安装应用时,依赖包的相应版本就会被自动安装。但是通常情况下,手动写依赖会比较麻烦,我们可以使用 pipreqs 首先自动生成 requirement.txt 文件,接着读取这部分文件即可。
- install_requires=[i.strip() for i in open(os.path.join(os.path.dirname(__file__), 'requirements.txt')).readlines() if i.strip()],
entry_points 的说明
entry_points 可以用来创建控制台脚本。我们看上面的例子就会非常好理解:
- entry_points = {
- 'console_scripts': [
- 'test = test.help:main'
- ]
- }
这样在安装完毕之后,我们可以直接在控制台输入 test
,这样是可以运行 test.help
模块下的 main
函数。
执行安装文件
在有了上面的 setup.py
文件之后,我们就可以进行打包,也可以将应用安装在本地的 python 环境中了。一共有以下的四种安装方式:
创建 egg 包
下面的命令会在当前目录下的 dist
目录内创建一个 egg
文件。文件名格式就是 应用名-版本号-python版本.egg
。同时你会注意到,当前目录多了 build
和 应用名.egg-info
子目录来存放打包的中间结果。(主要是看 dist 目录下的内容)
- python setup.py bdist_egg
创建 tar.gz 包
这个命令和上例类似,只不过创建的文件类型是 tar.gz,文件名为 应用名-版本号.tar.gz
。也是保存在 dist 文件夹下。
- python setup.py sdist --formats=gztar
安装应用
下面的安装命令会将当前的 python 应用安装到当前 python 环境的 site-packages
目录下,这样其他程序就可以像导入标准库一样导入该应用的代码了。
- python setup.py install
这里我们如果想要删除安装的包,可以使用 pip uninstall xxx
来完成删除。
以开发方式安装
如果应用在开发过程中会频繁变更,每次安装还需要先将原来的版本卸掉,这样就会很麻烦。如果使用 develop
开发方式安装的话,应用代码不会真的被拷贝到本地 python
环境的 site-packages
目录下,而是在 site-packages
目录里创建一个指向当前应用位置的链接。这样如果当前位置的源码被改动,就会马上反映到 site-packages
里。
- python setup.py develop
我们还可以使用 pip install -e
这种方式来「已开发方式安装」。这里 -e
的含义是,install a project in editable mode (i.e. setuptools "develop mode") from a local project path or a vcs url.
例如我们进入要安装的库所在的文件夹,使用下面的命令进行安装:
- pip install -e .