1.2.2自述文件
readme.md是当前模块的描述工具,通常采用markdown格式编写:
funker是一个优秀的工具1.2.3demos目录
该文件夹通常包含模块的一些使用示例,以便用户快速应用模块进行开发;
1.2.4 设置.py
setup.py文件可能是一个配置文件,用于向setuptools提供一些模块相关的信息,如:模块名称、模块版本、适用的python版本、作者、github地址等;
import setuptools
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="fucker", # 模块名称
version="1.0", # 当前版本
author="wupeiqi", # 作者
author_email="wupeiqi@live.com", # 作者邮箱
description="一个非常NB的包", # 模块简介
long_description=long_description, # 模块详细介绍,这里可以读取readme文件
long_description_content_type="text/markdown", # 模块详细介绍格式
# url="https://github.com/wupeiqi/fucker", # 模块github地址
packages=setuptools.find_packages(), # 自动找到项目中导入的模块
# 模块相关的元数据
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
# 依赖模块
install_requires=[
'pillow',
],
python_requires='>=3',
)
说明:setuptools是一个包管理工具,用于打包和安装模块;
1.2.5fucker目录
插件内容,可以在这里编译相关代码wp.py
def func():
print("一个神奇的包")
最终文件如下所示:
fucker
├── LICENSE
├── README.md
├── demos
├── fucker
│ ├── __init__.py
│ └── wp.py
└── setup.py
1.3 包装
上述步骤编译完文件夹和代码后,需要对代码进行打包。
1.3.1 安装打包工具
打包代码需要先安装setuptools和wheel,可以单独安装也可以pip安装,所以手动安装这两个工具。
由于Python3的安装自带了安装pip的功能,因此如果安装了Python3则这两个打包工具是免安装的;
注意:对于已经安装的用户,如果想要更新setuptools和wheel这两个工具,可以使用以下命令:
python -m pip install --upgrade setuptools wheel
1.3.2 封装代码
# 在终端中进入setup所在的目录;执行如下语句
python setup.py sdist bdist_wheel
打包后路径如下
fucker
├── LICENSE
├── README.md
├── fucker
│ ├── __init__.py
│ └── wp.py
├── fucker.egg-info
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ ├── dependency_links.txt
│ └── top_level.txt
├── build
│ ├── bdist.macosx-10.6-intel
│ └── lib
│ └── fucker
│ ├── __init__.py
│ └── wp.py
├── demos
├── dist
│ ├── fucker-0.0.1-py3-none-any.whl
│ └── fucker-0.0.1.tar.gz
└── setup.py
打包后的文件如下,旁边有详细说明;
1.4 上传与发布
文件打包后,需要将打包后的文件上传到PyPI。 如果要上传,需要先注册一个账号。
1.5 深入学习的安装和使用2.setup.py
以上打包命令:
# 在终端中进入setup所在的目录;执行如下语句
python setup.py sdist bdist_wheel
Python已经发展很多年了,项目打包的工具也非常成熟; 你可能听说过 disutils、distutils、distutils2、setuptools 等编译pip源码,看起来很熟悉,但它们的模式化程度很高。 他们之间是什么关系? 它们之间的关系可以参见参考文档中的详细解释。 可以简单理解为上面几个不是很成熟的setuptools
2.1 设置工具
setuptools 是一个优秀、可靠的 Python 包安装和分发工具。
安装 setuptools 有两种主要形式:
2.1.1 简易安装
注:该命令不是很常用,简单理解即可;
# 通过包名,从PyPI寻找最新版本,自动下载、编译、安装
$ easy_install pkg_name
# 通过包名从指定下载页寻找链接来安装或升级包
$ easy_install -f http://pythonpaste.org/package_index.html
# 指定线上的包地址安装
$ easy_install http://example.com/path/to/MyPackage-1.2.3.tgz
# 从本地的 .egg 文件安装
$ easy_install xxx.egg
# 在安装时你可以添加额外的参数
指定安装目录:--install-dir=DIR, -d DIR
指定用户安装:--user
以上仅介绍了easy_install的一些常用技巧。 想了解更多可以点击官方文档:
总结一下:setuptools是官方提供的一款专业的包分发工具。 从安装来看,它的功能确实很简单。 它更大的意义在于,对于软件包分发来说非常有用,而且程序多样化程度很高。 我们仍然使用它来发布版本包。
2.2 源码包和补码包
Python包分为两种:源码包和补码包;
2.2.1 以源码形式发布
安装源码包的过程是先解压,然后编译,最后再安装,所以是跨平台的,因为每次安装都需要编译,安装速度相对较慢二补安装包安装的形式;
源码包的本质是一个压缩包,其常见格式如下:
格式后缀
压缩
。压缩
广州塔尔
.tar.gz
兹塔尔
.tar、Z
柏油
。柏油
最常用的是.tar.gz,一般在linux下使用;
2.2.2 发布为二补包
二补代码包省去了编译过程,可以直接解压安装,因此安装速度比源码更快。 由于不同平台编译的包不兼容,所以需要提前编译好多个平台的包。
二进制补码数据包的常见格式是:
格式后缀
蛋
。蛋
车轮
.whl
Egg格式是setuptools在2004年引入的,Wheel格式是在2012年PEP427定义的。Wheel的出现就是为了取代Egg。 它的本质是一个zip包,现在被认为是Python的二进制补码包的标准格式。
这两种格式有什么区别?
可以通过pip安装wheel包,但是需要先安装wheel模块,然后再使用pip命令。
$ pip install wheel
$ pip wheel --wheel-dir=/local/wheels pkg
** 注:** 可以直接安装 pipinstallxxx.whl
2.3 setup.py解释
在上面的打包案例中,我们可以发现最重要的是setup.py文件。
import setuptools
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="fucker", # 模块名称
version="1.0", # 当前版本
author="wupeiqi", # 作者
author_email="wupeiqi@live.com", # 作者邮箱
description="一个非常NB的包", # 模块简介
url="https://github.com/wupeiqi/fucker", # 模块github地址
packages=setuptools.find_packages(), # 自动找到项目中导入的模块
)
这是上面打包文件的缩小版,下面我们将逐步扩展setup.py功能以减少更多参数;
2.3.1 节目分类信息
classifiers参数描述了包的分类信息。 有关所有支持的分类的列表,请参阅:%3Aaction=list_classifiers
# 模块相关的元数据
classifiers=[
"Programming Language :: Python :: 3", # 目标 Python 的版本
"License :: OSI Approved :: MIT License", # 许可证信息
"Operating System :: OS Independent", # 操作系统
# 发展时期,常见的如下
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha', # 开发状态
# 开发的目标用户
'Intended Audience :: Developers',
# 属于什么类型
'Topic :: Software Development :: Build Tools'
]
最常见的系统编译信息。 第一种情况,我们只写了3个。如果是个人使用的工具包,则不需要填写复杂的信息;
2.3.2 文件分发
setuptools.setup(
name="fucker", # 模块名称
version="1.0", # 当前版本
author="wupeiqi", # 作者
author_email="wupeiqi@live.com", # 作者邮箱
description="一个非常NB的包", # 模块简介
url="https://github.com/wupeiqi/fucker", # 模块github地址
packages=setuptools.find_packages(), # 自动找到项目中导入的模块
# 安装过程中,需要安装的静态文件,如配置文件、service文件、图片等
data_files=[
('', ['conf/*.conf']),
('/usr/lib/systemd/system/', ['bin/*.service']),
],
# 希望被打包的文件
package_data={
'':['*.txt'],
'bandwidth_reporter':['*.txt']
},
# 不打包某些文件
exclude_package_data={
'bandwidth_reporter':['*.txt']
}
)
除了上面的参数配置之外,还可以使用一个名为MANIFEST.in的文件来控制文件的分发。 下面是一个 MANIFET.in 文件示例:
include *.txt
recursive-include examples *.txt *.py
prune examples/sample?/build
该配置指定了以下几点
MANIFEST.in需要放在与setup.py同级的顶级目录下,setuptools会手动读取该文件。
一般打包时不需要大量的文件,所以我们也会直接在setup.py文件中使用;
2.3.4 依赖包下载
from setuptools import setup, find_packages
setup(
...
# 表明当前模块依赖哪些包,若环境中没有,则会从pypi中下载安装
install_requires=['docutils>=0.3'],
# setup.py 本身要依赖的包,这通常是为一些setuptools的插件准备的配置
# 这里列出的包,不会自动安装。
setup_requires=['pbr'],
# 仅在测试时需要使用的依赖,在正常发布的代码中是没有用的。
# 在执行python setup.py test时,可以自动安装这三个库,确保测试的正常运行。
tests_require=[
'pytest>=3.3.1',
'pytest-cov>=2.5.1',
],
# 用于安装setup_requires或tests_require里的软件包
# 这些信息会写入egg的 metadata 信息中
dependency_links=[
"http://example2.com/p/foobar-1.0.tar.gz",
],
# install_requires 在安装模块时会自动安装依赖包
# 而 extras_require 不会,这里仅表示该模块会依赖这些包
# 但是这些包通常不会使用到,只有当你深度使用模块时,才会用到,这里需要你手动安装
extras_require={
'PDF': ["ReportLab>=1.2", "RXP"],
'reST': ["docutils>=0.3"],
}
)
以上是各种情况下的参数说明,最常用的是第一个install_requires。 该参数最常用的用法如下:
2.3.5 安装环境限制
有些库并不适用于所有 Python 版本。 如果一个库安装在不兼容的Python环境下,理论上在使用时不应该报错,但在安装过程中应该会失败,提示严禁安装。
这样的功能可以使用python_requires来实现。
setup(
...
python_requires='>=2.7, <=3',
)
2.3.6 生成可执行分发
from setuptools import setup, find_packages
setup(
name="mytest",
version="1.0",
author="wangbm",
author_email="wongbingming@163.com",
description="Learn to Pack Python Module",
url="http://iswbm.com/",
packages=find_packages(),
# 用来支持自动生成脚本,安装后会自动生成 /usr/bin/foo 的可执行文件
# 该文件入口指向 foo/main.py 的main 函数
entry_points={
'console_scripts': [
'foo = foo.main:main'
]
},
# 将 bin/foo.sh 和 bar.py 脚本,生成到系统 PATH中
# 执行 python setup.py install 后
# 会生成 如 /usr/bin/foo.sh 和 如 /usr/bin/bar.py
scripts=['bin/foo.sh', 'bar.py']
)
里面的脚本有sh和py后缀。 安装完成后,setuptools会完整连接到/usr/bin并添加可执行权限。
如果你想对这些文件进行一些更改,比如删除多余的后缀,你可以这样做
from setuptools.command.install_scripts import install_scripts
class InstallScripts(install_scripts):
def run(self):
setuptools.command.install_scripts.install_scripts.run(self)
# Rename some script files
for script in self.get_outputs():
if basename.endswith(".py") or basename.endswith(".sh"):
dest = script[:-3]
else:
continue
print("moving %s to %s" % (script, dest))
shutil.move(script, dest)
setup(
...
scripts=['bin/foo.sh', 'bar.py'],
cmdclass={
"install_scripts": InstallScripts
}
)
此方法类似于django使用django-adminstartprojectname。 我们猜测这是这些的包装形式。 稍后我们会阅读django的部分源码来分析这个命令的真正原理;
2.3.6 ext_modules
ext_modules 参数用于创建 C 或 C++ 扩展包。 虽然Extension实例列表,但每个Extension实例都描述了一个独立的扩展模块,扩展模块可以设置扩展包名称、头文件、源文件、链接库及其路径、宏定义和编辑参数等,如:
setup(
# other arguments here...
ext_modules=[
Extension('foo',
glob(path.join(here, 'src', '*.c')),
libraries = [ 'rt' ],
include_dirs=[numpy.get_include()])
]
)
2.3.7 指定发布
setup.py 中只能指定版本,不能指定版本。 如果需要更改版本号,可以使用--release参数指定
python setup.py bdist_rpm --release=20200617
setup.py中的参数非常多,看来不依赖文档来写一个setup.py并不是那么简单。 为了方便提醒,我整理了setup函数的一些常用参数:setup.py的参数很多,参考如下:
2.3.8 构建包 2.3.9 安装包
一般情况下,我们通过上面创建的源码包或者二补包来安装模块。
但是在编译setup.py的过程中,可能不是一步就能完成的,需要多次调试。 这个时候怎么测试我写的setup.py文件是否可用呢?
这时候你可以使用这个命令,它会将你的模块安装到系统全局环境中
# 虚拟环境中,可以直接安装到虚拟环境中;
$ python setup.py install
如果你的项目还处于开发阶段,频繁安装模块也是一个麻烦。
这时候就可以使用这个命令来安装了。 该方法并不真正安装包编译pip源码,而是在系统环境中创建一个软链接,指向包实际所在的目录。 那边改了包然后就不用安装就生效了,这样就可以调试了。
# 生产环境中安装;
$ python setup.py develop