新手如何发布Python项目开源包过程详解


Posted in Python onJuly 11, 2019

本文假设你在 GitHub 上已经有一个想要打包和发布的项目。

第 0 步:获取项目许可证

在做其他事之前,由于你的项目要开源,因此应该有一个许可证。获取哪种许可证取决于项目包的使用方式。开源项目中一些常见许可证有 MIT 或 BSD。

要在项目中添加许可证,只需参照以下链接中的步骤,将 LICENSE 文件添加到项目库中的根目录即可:  https://help.github.com/en/articles/adding-a-license-to-a-repository

第 1 步:让你的代码准备就绪

要将项目进行打包,你需要做一些预备工作:

  • 让你的项目结构正确就位。通常情况下,项目库的根目录包含一个以项目名称命名的文件夹,项目的核心代码应该位于此文件夹中。在这个文件夹之外是运行和构建包(测试、文档等)所需的其他代码。
  • 核心文件夹应包括一个(或多个)模块和一个 __init__.py 文件,该文件包含你希望让终端用户访问的类/函数。此文件还可以包含包的版本,以便于终端用户访问。
  • 理想情况下,应使用 logging 包来设置合理的日志记录系统(而不是用 prints 输出)。
  • 理想情况下,应将你的核心代码分配到一个或多个类中。

from .estimate import Estimator

以__init__.py 为例,如果 Estimator 是终端用户将会访问的类(该类在 estimate.py 文件中定义)

import logging
class LogMixin(object):
 @property
 def logger(self):
 name = '.'.join([self.__module__, self.__class__.__name__])
 FORMAT = '%(name)s:%(levelname)s:%(message)s'
 logging.basicConfig(format=FORMAT, level=logging.DEBUG)
 logger = logging.getLogger(name)
 return logger

以日志系统为例:LogMixin 类可以在其他任何类中使用

第 2 步:使用打包工具创建 setup.py

在你的项目有了一套结构之后,你应该在项目库的根目录下添加 setup.py 文件。这有助于所有发布和版本维护过程的自动化。以下是 setup.py 的例子(源代码:https://github.com/nathan-toubiana/scitime/blob/master/setup.py)。

from setuptools import setup
from os import path
DIR = path.dirname(path.abspath(__file__))
INSTALL_PACKAGES = open(path.join(DIR, 'requirements.txt')).read().splitlines()
with open(path.join(DIR, 'README.md')) as f:
 README = f.read()
setup(
 name='scitime',
 packages=['scitime'],
 description="Training time estimator for scikit-learn algorithms",
 long_description=README,
 long_description_content_type='text/markdown',
 install_requires=INSTALL_PACKAGES,
 version='0.0.2',
 url='http://github.com/nathan-toubiana/scitime',
 author='Gabriel Lerner & Nathan Toubiana',
 author_email='toubiana.nathan@gmail.com',
 keywords=['machine-learning', 'scikit-learn', 'training-time'],
 tests_require=[
 'pytest',
 'pytest-cov',
 'pytest-sugar'
 ],
 package_data={
 # include json and pkl files
 '': ['*.json', 'models/*.pkl', 'models/*.json'],
 },
 include_package_data=True,
 python_requires='>=3'
)

setup.py 文件的示例

几点注意事项:

  • 如果你的包有依赖项,处理这些依赖项的简单方法是在配置文件中通过 install_requires 参数来添加依赖项(如果列表很长,你可以像之前那样指向一个 requirement.txt 文件)。
  • 如果你希望在任何人安装包时(从项目库中)下载元数据,则应通过 package_data 参数来添加这些元数据。
  • 有关 setup() 函数的更多信息,请参见:https://setuptools.readthedocs.io/en/latest/setuptools.html

注意:第 3 步到第 6 步是可选的(但强烈推荐),但是如果你现在马上想发布你的包,可以直接跳到第 7 步。

第 3 步:设置本地测试和检查测试覆盖率

此时还没有完成,你的项目还应该有单元测试。尽管有许多框架能帮助你做到,但一种简单的方法是使用 pytest。所有测试都应该放在一个专用的文件夹中(例如名为 tests/或 testing 的文件夹)。在这个文件夹中放置你需要的所有测试文件,以便尽可能多地包含你的核心代码。下面是一个如何编写单元测试的示例。这里还有一个 SciTime 的测试文件。

一旦就位,你就可以通过在项目库的根目录运行 python -m pytest 在本地进行测试。

创建测试后,你还应该能估算覆盖率。这一点很重要,因为你希望尽可能多地测试项目中的代码量(以减少意外的 bug)。

很多框架也可以用于计算覆盖率,对于 SciTime,我们使用了 codecov。你可以通过创建.codecov.yml 文件来决定允许的最小覆盖率阈值,还可以通过创建.coveragerc 文件来决定要在覆盖率分析中包含哪些文件。

comment: false
coverage:
 status:
 project:
 default:
 target: auto
 threshold: 10%
 patch:
 default:
 target: auto
 threshold: 10%

.codecov.yml 文件示例

[run]
branch = True
source = scitime
include = */scitime/*
omit =
 */_data.py
 */setup.py

coveragerc 文件示例

第 4 步:标准化语法和代码风格

你还需要确保你的代码遵循 PEP8 准则(即具有标准样式并且语法正确)。同样,有很多工具可以帮助你解决。这里我们用了 flake8。

第 5 步:创建一个合理的文档

现在你的项目已经测试过了,结构也很好了,是时候添加一个合理的文档。首先是要有一个好的 readme 文件,它会在你的 Github 项目库的根目录上显示。完成后,加上以下几点会更好:

  • Pull 请求和 issue 模板:当创建新的 Pull 请求或 issue 时,这些文件可以根据你的需求给你的描述提供模板。
  • Pull 请求创建步骤:https://help.github.com/en/articles/creating-a-pull-request-template-for-your-repository
  • issue 创建步骤:https://help.github.com/en/articles/manually-creating-a-single-issue-template-for-your-repository
  • Pull 请求模板:https://github.com/nathan-toubiana/scitime/blob/master/.github/PULL_REQUEST_TEMPLATE.md
  • issue 模板:https://github.com/nathan-toubiana/scitime/tree/master/.github/ISSUE_TEMPLATE
  • 贡献指南(contribution guide)。应该在贡献指南中简单地说明你希望外部用户如何协助你改进这个包。Scitime 的贡献指南参见:https://github.com/nathan-toubiana/scitime/blob/master/.github/CONTRIBUTING.md。
  • 准则,Scitime 的准则参见:https://github.com/nathan-toubiana/scitime/blob/master/.github/CODE_OF_CONDUCT.md
  • 标签和说明(见下面的截图)
  • readme 文件中的标签(推荐一篇如何使用标签的好文章:https://medium.freecodecamp.org/how-to-use-badges-to-stop-feeling-like-a-noob-d4e6600d37d2)。

由于 readme 文件应该相当综合,因此通常会有一个更详细的文档。你可以用 sphinx 来完成,然后在 readthedocs 上管理文档。与文档相关的文件通常放在 docs/文件夹中。sphinx 和 readthedocs 相关教程:

https://docs.readthedocs.io/en/stable/intro/getting-started-with-sphinx.html。

新手如何发布Python项目开源包过程详解

包含标签和说明的项目库示例

第 6 步:创建持续集成

此时,你的项目离发布就绪不远了。但是,在每次提交之后,必须更新文档、运行测试以及检查样式和覆盖率似乎有点难以应付。幸运的是,持续集成(CI)可以帮助你完成。你可以在每次提交之后使用 GitHub 的 webhook 来自动执行所有的这些操作。以下是我们在 SciTime 中使用的一套 CI 工具:

  • 对于运行测试,我们使用了 travis ci 和 appveyor(用于 Windows 平台上的测试)。对于 Travis CI,除了在项目库上设置 webhook 之外,你还必须创建一个.travis.yml 文件,在该文件中,你不仅可以运行测试,还可以上传更新的覆盖率输出以及检查样式和格式。通过创建 appveyor.yml 文件,appveyor 也可以这样做。
  • codecov 和 readthdocs 也有专用的 webhook
language: python
python:
 - "3.6"
# command to install dependencies
install:
 - pip install -r requirements.txt
 - pip install flake8
 - pip install pytest-cov
 - pip install codecov
# command to run tests
script:
 - python -m pytest --cov=scitime
 - ./build_tools/flake_diff.sh
after_success:
 - codecov

.travis.yml 文件的示例:请注意,每次提交,测试都需要与检查测试覆盖率一起进行。但还有一个 flake8 检查(逻辑则在 flake_diff.sh 文件中定义:https://github.com/nathan-toubiana/scitime/blob/master/build_tools/flake_diff.sh)

environment:
 matrix:
 - PYTHON: "C:Python36-x64"
install:
 # We need wheel installed to build wheels
 - "%PYTHON%python.exe -m pip install -r requirements.txt"
 - "%PYTHON%python.exe -m pip install pytest==3.2.1"
build: off
test_script:
 - "%PYTHON%python.exe -m pytest"

appveyor.yml 文件示例:这里我们只运行测试

这将使更新项目库的整个过程更加容易。

新手如何发布Python项目开源包过程详解

集成 webhook 的提交历史记录示例

第 7 步:创建你的第一个 release 和 publication

此时,你即将发布的包应与以下类似:

your_package/
 __init__.py
 your_module.py
docs/
tests/
setup.py
travis.yml
appveyor.yml
.coveragerc
.codecov.yml
README.md
LICENSE
.github/
 CODE_OF_CONDUCT.md
 CONTRIBUTING.md
 PULL_REQUEST_TEMPLATE.md
 ISSUE_TEMPLATE/

现在可以发布了!首先要做的是在 GitHub 上创建你的第一个 release——这是为了在给定的时间点跟踪项目的状态,每次版本更改时都需要创建新的 release。

完成后,唯一要做的就是发布包。发布 python 包最常见的平台是 PyPI 和 Conda。以下我们将描述如何用两者发布:

  • 对于 PyPI,首先需要创建一个帐户,然后用 twine 执行一些步骤:https://realpython.com/pypi-publish-python-package/。这应该相当简单,而且 Pypi 还提供了一个可以在实际部署之前使用的测试环境。PyPI 总体上包括创建源代码(python setup.py sdist)并使用 twine(twine upload dist/*)来上传。完成后,应该有一个与你的包对应的 PyPI 页面,并且任何人都应该能够通过运行 pip 命令来安装你的包。
  • 对于 Conda,我们推荐通过 conda forge 来发布你的包,conda forge 是一个社区,帮助你通过 conda 渠道发布和维护包。你可以按照以下步骤将包添加到社区:https://conda-forge.org/#add_recipe,然后你会被添加到 conda forge Github 组织中,并能够非常轻松地维护你的包,然后任何人都可以通过运行 conda 命令来安装你的包。

完成!

现在,你的包应该已经发出去,并且任何人都可以使用了!虽然大部分工作都完成了,但是你仍然需要维护你的项目,你需要进行一些更新:这大体上意味着每次进行重大更改时都要更改版本,创建新的 release,并再次执行第 7 步。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python smtplib模块发送SSL/TLS安全邮件实例
Apr 08 Python
Python中的字典与成员运算符初步探究
Oct 13 Python
举例讲解Python设计模式编程中对抽象工厂模式的运用
Mar 02 Python
Python中线程的MQ消息队列实现以及消息队列的优点解析
Jun 29 Python
python自动裁剪图像代码分享
Nov 25 Python
创建pycharm的自定义python模板方法
May 23 Python
Python 字符串转换为整形和浮点类型的方法
Jul 17 Python
python实现简单聊天室功能 可以私聊
Jul 12 Python
python Web flask 视图内容和模板实现代码
Aug 23 Python
python统计指定目录内文件的代码行数
Sep 19 Python
python 实现将Numpy数组保存为图像
Jan 09 Python
python实现批量移动文件
Apr 05 Python
让Python脚本暂停执行的几种方法(小结)
Jul 11 #Python
python在openstreetmap地图上绘制路线图的实现
Jul 11 #Python
Python使用pyautocad+openpyxl处理cad文件示例
Jul 11 #Python
python实现微信自动回复机器人功能
Jul 11 #Python
Python基于Opencv来快速实现人脸识别过程详解(完整版)
Jul 11 #Python
python 利用浏览器 Cookie 模拟登录的用户访问知乎的方法
Jul 11 #Python
PowerBI和Python关于数据分析的对比
Jul 11 #Python
You might like
PHP的SQL注入过程分析
2012/01/06 PHP
php字符编码转换之gb2312转为utf8
2013/10/28 PHP
php函数serialize()与unserialize()用法实例
2014/11/06 PHP
WordPress分页伪静态加html后缀
2016/06/08 PHP
PHP通过文件路径获取文件名的实例代码
2018/10/14 PHP
php中的钩子理解及应用实例分析
2019/08/30 PHP
jQuery 获取、设置HTML或TEXT内容的两种方法
2014/05/23 Javascript
深入浅出理解javaScript原型链
2015/05/09 Javascript
快速学习jQuery插件 Cookie插件使用方法
2015/12/01 Javascript
浅谈Javascript数据属性与访问器属性
2016/07/26 Javascript
Vue.js第三天学习笔记(计算属性computed)
2016/12/01 Javascript
基于JavaScript实现活动倒计时效果
2017/04/20 Javascript
Vue组件化通讯的实例代码
2017/06/23 Javascript
微信小程序中post方法与get方法的封装
2017/09/26 Javascript
AngularJS与后端php的数据交互方法
2018/08/13 Javascript
利用d3.js力导布局绘制资源拓扑图实例教程
2019/01/08 Javascript
jQuery实现可以计算进制转换的计算器
2020/10/19 jQuery
[01:01:29]2018DOTA2亚洲邀请赛 4.4 淘汰赛 VP vs Liquid 第一场
2018/04/05 DOTA
Python实现向QQ群成员自动发邮件的方法
2014/11/19 Python
使用Python的Tornado框架实现一个Web端图书展示页面
2016/07/11 Python
sublime python3 输入换行不结束的方法
2018/04/19 Python
python3.4 将16进制转成字符串的实例
2019/06/12 Python
Python2.7:使用Pyhook模块监听鼠标键盘事件-获取坐标实例
2020/03/14 Python
小学运动会广播稿200字(十二篇)
2014/01/14 职场文书
优秀经理获奖感言
2014/03/04 职场文书
课程改革实施方案
2014/03/16 职场文书
小学毕业寄语大全
2014/04/03 职场文书
领导班子个人查摆问题对照检查材料
2014/10/02 职场文书
初三英语教学计划
2015/01/23 职场文书
2015年售票员工作总结
2015/04/29 职场文书
校园新闻稿范文
2015/07/18 职场文书
2015初中团支部工作总结
2015/07/21 职场文书
python学习之panda数据分析核心支持库
2021/05/07 Python
Elasticsearch 聚合查询和排序
2022/04/19 Python
windows server 2012安装FTP并配置被动模式指定开放端口
2022/06/10 Servers
使用Redis实现分布式锁的方法
2022/06/16 Redis