DevOps目前并没有权威的定义,普遍认为,DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件。
作者以 dukepy 系列项目中 dkimageapp 子项目(关于图像处理的实用工具Python依赖库模块)的发布为例,详细解释了发布的每个步骤。作者建议与 dkimageapp 项目一样,在构建整个项目的时候,使用项目模板来进行初始化构建,这样项目结构也比较优秀,推荐 cookiecutter-pypackage(快速建立工程模板的Python命令行工具)项目。使用示例:
pip install cookiecuttercookiecutter https://gitee.com/siq/cookiecutter-pypackage.git
dkimageapp 代码和文档托管于Gitee:
61Duke/dkimageappgitee.com作者在2017-09-27写的《打包自己写的python库(betubedl)并且发布到pypi上》上有一段对pypi和pip挺有意思说法,不见得正确,做此记录:
pip 是一个现代的,通用的 Python 包管理工具。提供了对Python 包的查找、下载、安装、卸载的功能。而PyPI(Python Package Index)是python官方的第三方库的仓库,所有人都可以下载第三方库或上传自己开发的库到PyPI。PyPI推荐使用pip包管理器来下载第三方库。所以这两者在我看来,就是父子关系。PyPI带领着pip这个包管理器为python的开源资源库夜以继日地忙碌着。
注意:本文假设你已经有一个想要打包和发布的项目。
第 0 步:获取项目许可证
在做其他事之前,由于你的项目要开源,因此应该有一个许可证。获取哪种许可证取决于项目包的使用方式。开源项目中一些常见许可证有 MIT 或 BSD。如果是公司企业私有项目,最好也有类似的许可证声明,允许或者不允许使用者就行转载、使用,这样项目生态会更加规范。当然,这个不是必要的。
cookiecutter-pypackage 项目中提供可以选择的开源许可证,直接使用就好。
第 1 步:让你的代码准备就绪
要将项目进行打包,你需要做一些预备工作:
- 让你的项目结构正确就位。通常情况下,项目库的根目录包含一个以项目名称命名的文件夹,项目的核心代码应该位于此文件夹中。在这个文件夹之外是运行和构建包(测试、文档等)所需的其他代码。
- 核心文件夹应包括一个(或多个)模块和一个 __init__.py 文件,该文件包含你希望让终端用户访问的类/函数。此文件还可以包含包的版本,以便于终端用户访问。
- 理想情况下,应使用 logging 包来设置合理的日志记录系统(而不是用 print 输出)。
- 理想情况下,应将你的核心代码分配到一个或多个类中。
cookiecutter-pypackage 项目中上述项目准备工作,直接使用就好。
以 dkimageapp 项目为例:
第 2 步:使用打包工具创建 setup.py
在你的项目有了一套结构之后,你应该在项目库的根目录下添加 setup.py
文件。这有助于所有发布和版本维护过程的自动化。以下是 dkimageapp 的 setup.py
的示例:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Copyright (c) 61DUke.# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Readme Document for more details.
# Create: 2020-12-27"""The setup script."""from setuptools import setup, find_packages
import oswith open("README.rst", "r", encoding="utf-8") as readme_file:readme = readme_file.read()with open("HISTORY.rst", "r", encoding="utf-8") as history_file:history = history_file.read()dir_ = os.path.dirname(os.path.abspath(__file__))
requirements = open(os.path.join(dir_, "requirements.txt"), "r", encoding="utf-8").read().splitlines()setup_requirements = ["pytest-runner", ]test_requirements = ["pytest>=3", ]setup(author="61Duke",author_email="loveweihaitong@foxmail.com",python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",classifiers=["Development Status :: 2 - Pre-Alpha","Intended Audience :: Developers","License :: OSI Approved :: MIT License","Natural Language :: English","Programming Language :: Python :: 2","Programming Language :: Python :: 2.7","Programming Language :: Python :: 3","Programming Language :: Python :: 3.5","Programming Language :: Python :: 3.6","Programming Language :: Python :: 3.7",],description="dkimageapp是61Duke于2020年整合工作与学习研发关于图像处理的实用工具Python依赖库模块,该模块统一规范的API""接口,承载个人未来工作中开发有关图像处理实际应用。该模块由算法科学家61Duke独家研发,提供图像裁剪、合并、图像格式转换、""色调占比提取、颜色相似度、图像定位和图像检索等功能。dkimageapp 模块为各个项目和业务提供支持。",entry_points={"console_scripts": ["dkimageapp=dkimageapp.cli:main",],},install_requires=requirements,license="MIT license",long_description=readme + "nn" + history,include_package_data=True,keywords="dkimageapp",name="dkimageapp",packages=find_packages(include=["dkimageapp", "dkimageapp.*"]),setup_requires=setup_requirements,test_suite="tests",tests_require=test_requirements,url="https://gitee.com/weihaitong/dkimageapp",version="0.1.0",zip_safe=False,
)
cookiecutter-pypackage 项目中也会将setup.py
生成好,直接使用就好。
注意事项:
- 如果你的包有依赖项,处理这些依赖项的简单方法是在配置文件中通过 install_requires 参数来添加依赖项(如果列表很长,你可以像上面那样指向一个 requirements.txt 文件)。
- 如果你希望在任何人安装包时(从项目库中)下载元数据,则应通过 package_data 参数来添加这些元数据。
- 有关 setup() 函数的更多信息,请参见:setuptools 文档
注意:第 3 步到第 6 步是可选的(但强烈推荐),但是如果你现在马上想发布你的包,可以直接跳到第 7 步。
第 3 步:设置本地测试和检查测试覆盖率
此时还没有完成,你的项目还应该有单元测试。尽管有许多框架能帮助你做到,但一种简单的方法是使用 pytest。所有测试都应该放在一个专用的文件夹中(例如名为 tests/或 testing 的文件夹)。在这个文件夹中放置你需要的所有测试文件,以便尽可能多地包含你的核心代码。
第 4 步:标准化语法和代码风格
你还需要确保你的代码遵循 PEP8 准则(即具有标准样式并且语法正确)。同样,有很多工具可以帮助你解决。这里我们用了 flake8。
第 5 步:创建一个合理的文档
现在你的项目已经测试过了,结构也很好了,是时候添加一个合理的文档。首先是要有一个好的 readme 文件,它会在你的代码托管项目库的根目录上显示。
由于 readme 文件应该相当综合,因此通常会有一个更详细的文档。你可以用 sphinx 来完成,然后在 readthedocs 上管理文档。与文档相关的文件通常放在 docs/文件夹中。sphinx 和 readthedocs 相关教程。
cookiecutter-pypackage 项目中也会生成很多标准的项目文档和作者、贡献和历史等文档,直接使用就好。
以下是 dkimageapp 的 README.rst
的示例:
第 6 步:创建持续集成
此时,你的项目离发布就绪不远了。但是,在每次提交之后,必须更新文档、运行测试以及检查样式和覆盖率似乎有点难以应付。幸运的是,持续集成(CI)可以帮助你完成。你可以在每次提交之后使用 GitHub 的 webhook 来自动执行所有的这些操作。
第 7 步:创建你的第一个 release 和 publication
构建发布版本的包
在项目根目录下使用 python setup.py sdist bdist_wheel
,这将在新创建的dist
目录中创建两个文件,一个源归档文件和一个wheel
文件。以 dkimageapp 项目为例:
开源:
PyPI:首先需要创建一个帐户(注册传送门PyPI),其次在项目根目录下使用 twine upload dist/*
去上传并发布包给开源的PyPI社区仓库。
私有(使用pypiserver
):
- 安装依赖 :
pip install pypiserver passlib
- 创建packages目录
- 以无认证方式启动pypiserver:
pypi-server -p 8080 -P . -a . ./packages
- 上传到私有pypi服务:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
以 dkimageapp 项目为例:
使用密码保护PyPI源
当希望使用密码来控制Python包的上传操作的时候, 需要使用Apache htpasswd 文件.
pypiserver 需要 passlib 包来读取 htpasswd 文件. 使用以下命令来安装 passlib :
pip install passlib
要生成 htpasswd 文件, 需要安装 apache2-utils 工具包. 在Ubuntu上使用以下命令安装:
apt-get install -y apache2-utils
接下来就可以用 htpasswd 命令来生成密码文件. 假设密码文件路径为 /root/.pypipasswd , 第一次生成密码文件的命令如下:
htpasswd -c /root/.pypipasswd sam
上述命令中的最后一个参数sam是用户名, 执行命令后, 会提示输入密码.
当需要在已有的密码文件中添加新的用户名和密码时, 不能再使用-c参数, 否则会将已有的数据覆盖. 比如, 要在上一步生成的文件里添加一个新用户名 john :
htpasswd /root/.pypipasswd john
接下来就可以使用密码文件来控制上传操作了. 当启动 pypiserver 时, 通过-P参数来指定所要使用的密码文件. 默认情况下, 上传操作会需要密码验证, 如果希望其他操作也需要密码验证, 可以使用-a参数. 具体-a参数的使用可以查阅_pypiserver_的启动命令帮助, 这里不再展开.
pypi-server -P /root/.pypipasswd
第 7 步:下载使用发布的库
以 dkimageapp 项目为例:
现在,你的包应该已经发出去,并且任何人/指定人可以使用了!虽然大部分工作都完成了,但是你仍然需要维护你的项目,你需要进行一些更新:这大体上意味着每次进行重大更改时都要更改版本,创建新的 release,并再次执行第 7 步。
本文为2017-09-27的《打包自己写的python库(betubedl)并且发布到pypi上》博客的迁移,并做了全面性扩展,日后在此继续更新内容...