0%

pypi安装包制作及发布

介绍如果将自己的程序制作成pypi包并发布到pypi

pypi简介

pypi全程是Python Package Index,其官方定义是

The Python Package Index is a repository of software for the Python programming language. There are currently 119827 packages here. – until 2017-10-21

我们平常安装程序所用的pip就是到pypi中找到相应的库并将其安装到本地的,比如我们运行

1
pip install requests

pip就会去pypi找到最符合requests的这个包,然后下载到本地,最后将其安装

pypi安装包制作

注意

pypi的库不允许有相同的名称,如果想要跟着教程完成相关的操作的话请先将教程的zhongjiajie改成你的名称(目的是在pypi找不到相应的库),才能完成库的上传操作

普通库

这里的普通库指的是通过from package import functionimport package方式调用的库,下面进行具体程序的演示,先切换到项目目录,这里是myproject

创建项目

1
2
3
4
cd
cd Desktop/
mkdir myproject
cd myproject/

定义库的功能

创建文件夹zhongjiajiepypi并且在其中编写简单的Python函数myfunction.py及定义init.py

1
2
3
4
mkdir zhongjiajiepypi
cd zhongjiajiepypi/
vim __init__.py # 这个文件作用就是给这个文件夹打成包
vim myfunction.py # 这里放置逻辑代码了

其中myfunction.py的内容为

1
2
3
4
5
6
7
8
9
10
cat myfunction.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-

def mysum(*args):
s = 0
for v in args:
i = float(v)
s += i
print s

init.py的内容为

1
2
$ cat __init__.py
from myfunction import mysum

编写项目setup.py文件

这是重点:接着要编写pypi的setup文件,生成pip可以识别的格式,为后期上传到pypi做准备,我们先切换到myproject根目录,然后编辑setup.py文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ vim setup.py         # 写入相应的setup.py内容 详见cat命令结果
$ cat setup.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from setuptools import setup, find_packages

setup(
name = "zhongjiajiepypi",
version = "0.0.1",
keywords = ("pip", "testpypi"),
description = "test pip module",
long_description = "test how to define pip module and upload to pypi",
license = "MIT",

url = "https://zhongjiajie.com", # your module home page, such as
author = "zhongjiajie", # your name
author_email = "zhongjiajie955@hotmail.com", # your email

packages = find_packages(),
include_package_data = True,
platforms = "any",
install_requires = []
)

这里我们需要注意一下,setup.py文件是能不能正确生成pip能识别文件的关键,他有自己的一套格式,我们编写setup文件要遵循这一套格式,实例代码是基础的设置,更多设置请查阅Writing the Setup Script

打包pypi

此时整个包已经编写完成了,整个项目的文件结构是

1
2
3
4
5
6
$ tree
.
├── zhongjiajiepypi
│   ├── __init__.py
│   └── myfunction.py
└── setup.py

现在我们需要将项目变成pip能够识别并安装的文件,在本地测试成功后将文件上传到pypi,在项目的根目录(setup.py同等位置)中运行

1
2
python setup.py sdist       # 生成二进制包 支持pip安装 推荐使用
python setup.py bdist_egg # 生成egg 支持easy_install安装

Python会自动将项目打包成二进制包,此时项目的文件结构是

1
2
3
4
5
6
7
8
9
10
11
12
13
tree
.
├── dist
│   └── zhongjiajiepypi-0.0.1.tar.gz
├── zhongjiajiepypi
│   ├── __init__.py
│   └── myfunction.py
├── zhongjiajiepypi.egg-info
│   ├── dependency_links.txt
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   └── top_level.txt
└── setup.py

此时已算完成了pypi的打包

本地测试

建议在将包上传到pypi之前现在本地完成测试工作,方法是先进入dist文件夹,然后用pip命令安装本地的二进制包,安装完成后测试其中的方法是否可用

1
2
3
4
$ cd dist
$ pip install zhongjiajiepypi-0.0.1.tar.gz
$ python -c "import zhongjiajiepypi; zhongjiajiepypi.mysum(3, 4, 5)"
12.0

可以看到结果是12.0证明包能达到预期,可以上传到pypi

上传到pypi

注意: 部分旧版教程会说先运行python setup.py register进行注册,然后再运行python setup.py sdist upload将二进制包上传到pypi上,但是目前pypi已经可以不用注册直接运行python setup.py sdist upload完成上传。

我们先尝试用python setup.py register,接着输入密码,结果收到下面的提示

1
2
Registering zhongjiajiepypi to https://upload.pypi.org/legacy/
Server response (410): Project pre-registration is no longer required or supported, so continue directly to uploading files.

可以看到确实不用先注册了,下面我们尝试直接运行python setup.py sdist upload,然后输入密码,结果让我吃了一斤

1
2
3
Submitting dist/zhongjiajiepypi-0.0.1.tar.gz to https://upload.pypi.org/legacy/
Upload failed (403): Invalid or non-existent authentication information.
error: Upload failed (403): Invalid or non-existent authentication information.

两种方法都不能将本地包上传到pypi,于是我google了原因,看到了github上面相关的链接Invalid or non-existent authentication information,要新建$HOME/.pypirc文件用于保存pypi的连接信息,尝试了@dover247的文件样例发现仍不能上传到pypi,然后看到@jaraco说那个版本有点旧,就去了The Python Package Index (PyPI)使用了最新的样例,然后再运行python setup.py sdist upload就能上传成功了(注意国内网络环境访问pypi)

CLI

CLI简介

CLI(command-line interface,命令行界面)是指可在用户提示符下键入可执行指令的界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。我个人的理解是通过命令行操作调用程序的接口,以达到我们的目的,好处是更加直观、并提供交互式的完成一些简单的操作

定义Python的CLI接口

Python的CLI和Python的一般库的做法类似,不同的是它暴露了一个CLI的关键字,调用起来就类似于调用python script_name.py args的形式。他会在$PYTHON_HOME/Scripts生成可运行文件,命令行调用,下面我们把之前的例子改成CLI的调用方式,先修改zhongjiajiefunction.py文件,加上命令行传参的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat zhongjiajiefunction.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-

def mysum(*args):
s = 0
for v in args:
i = float(v)
s += i
print s

# 从此是新加的功能
def mysum_cli():
import sys
args = sys.argv[1:]
mysum(*args)

新加的mysum_cli提供了在命令行获取相关的参数,并将参数传递给原来的mysum函数。接着修改setup.py函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ cat setup.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from setuptools import setup, find_packages

setup(
name = "zhongjiajiepypi",
version = "0.0.1",
keywords = ("pip", "testpypi"),
description = "test pip module",
long_description = "test how to define pip module and upload to pypi",
license = "MIT",

url = "https://zhongjiajie.com",
author = "zhongjiajie",
author_email = "zhongjiajie955@hotmail.com",

packages = find_packages(),
include_package_data = True,
platforms = "any",
install_requires = [],

# 此处起是增加的内容
entry_points = {
'console_scripts': [
'mysum=zhongjiajiepypi.zhongjiajiefunction:mysum_cli',
]
}
)

可以看到只需要在配置中加上entry_points入口选项就行了,其中console_scripts中指定命令行中的关键字,此处为mysum,对应的是zhongjiajiepypi这个库的zhongjiajiefunction函数里面的mysum_cli方法。

至此完成了CLI的配置,接着根据之前介绍的打包pypi的方法进行打包,然后本地测试运行就能得到我们想要的结果了,当和下面一样看到命令行调用mysum 2 3 4的结果是9.0的时候就说明CLI接口已经能正常运行了

1
2
3
4
5
$ python setup.py sdist
$ cd dist
$ pip install zhongjiajiepypi-0.0.1.tar.gz
$ mysum 2 3 4
9.0

Tips

  • 由于pypi不能有同名的库,所以拿样例测试的时候要将名字改成pypi不存在的库名
  • 上传到pypi已经不用先注册,但要新建$HOME/.pypirc文件填入适当的内容

References

怎么制作pip安装包,Python Egg

如何将自己的程序发布到 PyPI

How To Package Your Python Code