在之前这个实现json比较的库的帖子里,我把库上传pypi的时候,相当坑。而且pypi有个特点,就是你一旦弄错了,就不能删除原来的名字(但可以删库,也可以更新版本,就是不能替换)。所以上传时应该尽量谨慎。
1. 注册pypi的账号
访问pypi.org并点击register(有部分网络pypi访问速度较差,可能发生上传或下载失败的情况,请换个网络环境,或者自备代理)。可以使用QQ邮箱,它会要求你的邮箱验证。
如果你想使用pypitest来测试发布,也可以同时注册pypitest。
2. 处理路径。你的项目应该呈现这样的结构:
其中里层的是你要上传的包。而外层来写setup.py和readme。这两个将在后面介绍。dist是打包发布后自动生成的文件夹,里面有打成的包(python编译exe的同学应该对此不陌生,因为编译exe的输出路径一般也在dist里面),而MANIFEST也是自动生成。所以我们着重要做的就是__init__.py,还有reademe和setup.py这三个文件的编写。
3. 代码规范化。
在打包前应该注意一些事情。
- 整个代码中,除了
if __name__ == "__main__"
可以包含打印输出、调试的部分之外,其他地方都应该只有函数、类、全局变量等的定义。导入时不应该出现print等副作用。除非你确实希望如此例外。 - 在例子中,json_compare是我实现功能的库,而test_json_compare是测试用例。其中__init__.py文件则是python中将一个目录识别为包必不可少的文件,是访问包的入口。在内应导入所有需要暴露的类或函数。为兼容,最好如下图使用相对路径导入。(如果不是一个包,普通目录内这样写IDE会报错)
- 版本兼容。考虑你的代码究竟适合于哪些版本,并小心测试通过。在我的例子中,我支持了python2.x和3.x,所以特意使用six模块进行适配,有些地方需要去针对不同版本做不同的操作。另外,要考虑平台的兼容性。所以每个文件的头两行应该使用标准的方法来写,避免放到Linux的机器上不识别。
#!/usr/bin/env python
# coding: utf-8
- 编写注释和类型提示。尤其是针对对外暴露的方法编写注释。
使用一对三双引号,是python中函数和类注释文档的规范。函数写完后输入三个",pycharm会自动帮你形成文档骨架。:param表示参数,随后写参数的类型,最后是参数名,比如参数a的类型就是str/unicode/list/tuple/dict中的一种(实际上这显然是针对python2,3里面应该对应bytes,但这样写无妨),而参数ignore_list_seq类型则是bool。return下面也要写明返回值的类型。
这些类型不是必需的,但是有诸多好处。诸如Pycharm这样的IDE会自动针对返回值和参数提供类型提示和方法联想,比如若你使用了这个函数的返回值变量,那只有在返回值被注释为str类型或者IDE能自己判断出返回类型时,才会给你提供.join等方法的联想。同时,当用户传错了参数类型时,也会被IDE提示警告,从而引起用户警觉。这类动态语言应该非常注意类型的校验,否则容易发生幽灵bug,且代码的可读性,可调试性都会变差。
4. 编写readme.md文档
一个项目能做什么,很大程度取决于文档。要想类似下图这样,给你的项目在pypi页面上写个好的介绍,你需要准备项目的介绍文档。 强烈推荐给自己的项目准备文档。 我们这里使用我们熟悉的markdown。但需要注意的是,要么你安装twine且升级pip,配置新的选项,否则pypi不支持markdown,它支持的是rst文件(这个非常坑,如果搞错了格式,它也不会报错,不会有任何警告,就只是文档无法展示而已)。好在markdown和rst可以转换。我们稍后会用代码将其转换。
例如这上面的文档,上传后会产生如下效果
5. 准备转换文档的工具
需要安装一个转换文档格式的模块
pip install pypandoc
安装好后,我在其他项目源码中看到过类似的代码,但是总是发现文档无法展示。后来
去掉了上面的except,查看报错信息,结果发现pypandoc是需要依赖pandoc这个程序的,它只是pandoc的python接口。于是又去安装pandoc。在官网的这个链接可以下载安装程序。https://www.pandoc.org/installing.html安装比较简单。不过装好以后要配置环境变量。将下面图上的路径加入到path里。
保存后,重新打开cmd,验证能够通过where找到就算成功
6. 编写setup.py文件
仍然记得之前的规范(编码、python解释器路径等),示例如下:
#!/usr/bin/env python
# coding: utf-8
from distutils.core import setup
from os import path
this_directory = path.abspath(path.dirname(__file__))
try:
import pypandoc
long_description = pypandoc.convert('README.md', 'rst')
except:
long_description = ""
setup(
name='jsoncomparedeep',
version='1.12',
description='A recursive Json comparing library that handles list orders and fuzzy types',
author='Rainy Chan',
author_email='[email protected]',
url='https://rainydew.blog.csdn.net/article/details/93904318',
packages=['json_compare'],
install_requires=['six>=1.12.0'],
keywords='json compare comparison order unicode fuzzy',
long_description=long_description,
python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
)
一些注意点解释如下
- 使用path.abspath来活化路径,否则用户在pip下载安装你的包时,会被红色字体报错警告(大部分时候仍然可以安装),影响用户体验。
- long_description这里必须使用try处理。否则用户在pip安装时,也会执行此setup.py。若用户机没有pypandoc,或者虽然有但环境变量里找不到pandoc.exe,则都会报错导致安装失败。这一句话的用途是将markdown文档转换为rst格式文档并上传。
- name请在https://pypi.org先做搜索。不能和pypi上已有的项目重名,否则会上传失败。不要使用中文名。同时取名请慎重,因为一旦取好将不能再修改,只能取新的名字。这里有个小技巧,就是比如我做的是jsoncompare,但pypi上已经有了同样名字的项目,那么我如果要被搜索到,我应该取jsoncomparedeep这样的后缀,而非看起来更自然的deepjsoncompare。因为pypi会从开头来匹配,输入json compare,可以搜到jsoncomparedeep,却搜不到后者。
- version可以从0.1开始,也可以是三段的版本号比如0.1.0。当你更新升级了你的库以后,你只能修改version而不能修改名字来上传,否则pip install -U将不起作用。而且version只能越来越大。比如1.12之后的下一个版本只能从1.13开始。要小心的是,一个version一旦传上去了,就不能再修改。你可以删除,但即便删除,这个版本号也不能再使用,只能使用下一个版本号。pypi以此来保障包的一致性,即用户使用pip下载同样名字和同样的版本,不会下载到实际上不相同的包。如果你的包发现了严重bug,则应该尽快删除它并上传新版本。
- url是你的项目主页路径
- packages里应该取图上目录中,你的包的文件夹名(和setup.py同级的文件夹)。大的项目有多个文件夹,则列表写多个目录。
- install_requires这个非常重要,注意了,不是有些文章或者demo里的requires!!里面写你需要依赖的库(和其版本)的情况。只写非官方库。我的这个库引用了json re sys traceback和six,只有用于python2/3兼容的库six是三方库,所以我这里只写了six。最好要求指定版本号。如果你不清楚版本,可以用pip --list命令去查看你当前使用的版本。这一项的目的是能让pip自动处理依赖。比如用户安装我的pip install jsoncomparedeep,且系统发现这个用户还没有安装six库,就会自动一并安装six库,这样用户安装好我的库以后,就不会在import的时候报错。这个地方十分坑,我开始写的是文档里的requires,后来看了flask的源码的setup.py,才发现要这么写才能认得。
- long_description就是展示在首页的文档。而description会在搜索库的时候就展示,所以应该简练清晰的表明库的功能。例如
- python_requires可以防止用户使用不兼容的python版本来安装你的库。例如我上面的公式,则是要求用户的python版本为2.6~2.7,或3.5以上。
7. 建立 .pypirc 文件
对于Linux用户,直接在家目录下建立;对于windows用户,在运行-cmd里默认指向的路径下建立。windows系统会弱智到不允许你建立一个以英文.开头的文件。可以运行cmd,并使用这样的命令
回车后即可建立这个文件,请用notepad++之类的打开(不允许BOM,所以千万不要用记事本去修改)。编辑配置如下并保存。其中username和password写你在pypi和pypitest的用户名和密码。如果你不上传pypitest,下面的可以不要。最好以unix换行符(LF)作为文件的换行标志。
8. 上传到pypi
确保你的python.exe在环境变量内,否则需要提供python.exe的完整路径。
在setup.py的目录下打开cmd(可以pycharm里setup.py右键-在终端内打开)。然后输入
python setup.py sdist upload -r pypi
并回车,命令行提示200,即上传成功(如果是上传pypitest则命令改为pypitest)。随后请在pypi内查看自己的包,观察首页展示,并测试下载和安装。尤其是推荐在标准版python(没有三方库)的虚拟机等处测试安装。
在我的ubuntu虚拟机上测试安装
可以看到能够自动安装six模块,意味着能自动处理依赖。
然后在python中尝试导入并执行成功。
enjoy~