搭建PyPi仓库
安装依赖包
pypiserver
要搭建PyPi仓库,我们需要使用 pypiserver
库,这是一个最基本的 PyPI 服务器实现库,可以启动一个用来上传和维护Python包的服务器。
通过 pip install pypiserver 命令安装 pypiserver
库,该库在 Python 2x 或者 Python 3x 下均运行。
passlib
默认情况下,Python包的上传操作是无权限管理的,当我们希望使用密码来控制,只有指定用户才可以进行Python包的上传操作的时候,就需要使用 Apache htpasswd 文件,所以,我们需要 passlib
包来读取 Apache htpasswd 文件
通过 pip install passlib 命令安装 passlib
库,该库在 Python 2x 或者 Python 3x 下均运行。
那么 Apache htpasswd 文件是怎么生成的呢?我们需要安装 apache2-utils
工具包,以 Ubuntu 系统为例,使用下面命令安装:
$ sudo apt-get install -y apache2-utils
接下来,我们先使用 htpasswd
命令来生成一个 Apache htpasswd 文件:
$ pwd
/home/hekaiyou
$ ls -a
.
$ htpasswd -c /home/hekaiyou/.pypipasswd sam
New password: [输入密码]
Re-type new password: [再次输入密码]
Adding password for user sam
这样一个名为 sam 的用户就创建成功了,接下来我们在已有的 Apache htpasswd 文件中添加新的用户名及密码:
$ htpasswd /home/hekaiyou/.pypipasswd newuser
New password: [输入密码]
Re-type new password: [输入密码]
Adding password for user newuser
这样一个名为 newuser 的新用户也创建好了。
启动PyPI服务器
无认证方式启动
启动PyPI服务器之前需要在启动目录创建一个 packages 目录 (mkdir packages
),这个目录是用来Python包的,然后就可以启动PyPI服务器:
$ pypi-server -P . -a .
因为默认情况下,上传Python是需要密码的,不管我们可以通过上面的方式关闭密码保护, -P
参数指定密码,-a
参数指定需要密码保护的操作,我们把它们同时指定为 .
,表示所有的操作都不需要认证。
启动PyPI服务器,可以通过浏览器访问 http://localhost:8080/ 以打开PyPI服务器的默认欢迎页。
在没有显式指定启动参数的时候,pypiserver
库会使用 ~/packages 来保存Python包,同时监听 8080 端口来启动PyPI服务器。
认证方式启动
如果要控制用户上传Python包的操作,我们需要密码验证,在启动PyPI服务器时,通过 -P
参数来指定前面创建的 Apache htpasswd 文件。这样,用户上传Python库到私有仓库时,就会要求用户提供账户与密码。
接下来我们就可以用认证方式启动PyPI服务器了:
$ pypi-server -P /home/hekaiyou/.pypipasswd
监听端口与请求转发
通过 -p
参数可以指定PyPI服务器的端口,例如:
$ pypi-server -p 8090
私有PyPI服务器不可能包含社区所有的Python库,因此,当请求的Python包在本地上没有找到时,我们可以将请求转发到 外部PyPI源,以 阿里PyPI源 为例:
$ pypi-server --fallback-url https://mirrors.aliyun.com/pypi/simple/
这样就可以降低我们的维护成本,着重维护我们的私有内容,而不用作成一个镜像站点。
使用PyPi仓库
通过上一步,我们启动了私有PyPI服务器以后,我们可以将制作好的Python包上传到此目录下。
制作Python包
比如,我们有一个Python项目叫 hello_pypi
,项目根目录下有一个 setup.py 文件,内容如下:
import setuptools
import os
# 读取根目录下的 README.md 文件内容,作为项目包的详细介绍
CUR_DIR = os.path.abspath(os.path.dirname(__file__))
README = os.path.join(CUR_DIR, 'README.md')
with open('README.md', "r") as fd:
long_description = fd.read()
# 包含 "Required" 标识的参数为必填参数,缺少将无法上传到PyPI
# 包含 "Optional" 标识的参数为可选参数,可以被注释掉
setuptools.setup(
# 这是当前项目的名称,首次发布此包时,这个名称将作为注册名称
# 用户将通过这个名称来安装此项目包,例如:
#
# $ pip install sampleproject
#
# 项目名称的命名规范请查阅:
# https://packaging.python.org/specifications/core-metadata/#name
# Required
name='hello_pypi',
# 项目版本格式应符合 PEP 440 规范:
# https://www.python.org/dev/peps/pep-0440/
# Required
version='1.2a1',
# 用一行文本介绍当前项目包的主要功能或作用
# Optional
description='A simple hello pypi code',
# 当前项目包的具体描述,这是用户在访问PyPI时将看到的详细介绍
# Optional
long_description=long_description,
# 与上述的具体描述对应的内容格式,有效值包含:
# text/plain, text/x-rst, and text/markdown
# Optional
long_description_content_type='text/markdown',
# 指向当前项目的代码仓库或主页的有效链接
# Optional
url="https://github.com/hexiaoyou/hello_pypi",
# 当前项目包的作者或组织的名称
# Optional
author="Kaiyou He",
# 与上述作者或组织对应的邮件地址
# Optional
author_email="[email protected]",
# 如果项目包比较简单,那么可以在此处手动指定软件包目录
# 或者直接使用默认的 find_packages(),它会递归查找包的文件
#
# 另外,如果项目包中只有一个Python文件,请按下面的方式使用 `py_modules` 参数
# 这样会存在一个名为 `my_module` 的文件:
#
# py_modules=["my_module"],
#
# Required
packages=setuptools.find_packages(),
# 这里列出了当前项目包运行时依赖的其他项目包/库
# 安装项目包时,放置在此处的所有软件包/库都将通过 pip 同时安装
# 因此,它们必须是有效的库,否则将导致 pip 命令失败
# Optional
install_requires=[
'colorama>=0.4.1',
'PrettyTable'
],
# 当前的项目包的关键字,这些关键字将显示在项目页面上,告知用户,这个项目与什么有关?
# 请注意,这是一串用空格隔开的单词,而不是列表
keywords='demo pypi hello',
)
对应的根目录下还需要创建一个 README.md 文件,内容可以随便写。在打包之前我们可以验证 setup.py
文件的正确性:
$ python setup.py check
接下来我们需要进行打包操作,在项目根目录下执行:
$ python setup.py sdist
就这样,我们打好了一个空项目包。
上传Python包
无认证方式上传
上传命令与打包指令很像,就是后面加上 upload
参数,并用 -r
参数设置PyPI服务器地址:
$ python setup.py sdist upload -r http://localhost:8080
这样我们就可以通过 http://localhost:8080/simple/ 查看到我们刚才上传到项目包/库。
认证方式上传
认证方式上传的话,我们需要用到 twine
库,通过 pip install twine 命令安装 twine
库。
然后,在再次上传之前,我们需要改一下版本号,否则会报以下异常,即版本冲突的意思:
HTTPError: 409 Conflict from http://localhost:8080/
Conflict
我们可以在目录下添加一个 hello_pypi.py 文件,在里面设备写一个输出方法。
def demo():
print('Hello PyPI')
然后在 setup.py 文件中修改版本为 version='1.2a2'
。然后再通过以下命令进行验证打包:
$ python setup.py check # 先验证
$ python setup.py sdist # 再打包
这时,你会发现 dist 目录下出现了两个版本,这里存放的就是我们打出来的Python项目包/库。
因为有多个Python项目包/库,因此我们在上传时,要选择具体的 dist/hello_pypi-1.2a2.tar.gz
打包文件。
$ twine upload dist/hello_pypi-1.2a2.tar.gz --repository-url http://localhost:8080
下载使用Python包
就像从其他源下载第三方库一样,我们只要通过 -i
参数,就可以指定到我们自己的PyPI服务器。下载命令如下:
pip install hello_pypi -i http://localhost:8080
接下来就可以调用我们自己的Python包/库了:
>>> import hello_pypi
>>> hello_pypi.demo()
Hello PyPI
>>>