搭建、使用与维护私有PyPi仓库

搭建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服务器的默认欢迎页。

PyPI服务器的默认欢迎页.png

在没有显式指定启动参数的时候,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

就这样,我们打好了一个空项目包。

PyPI空项目包文件夹.png

上传Python包

无认证方式上传

上传命令与打包指令很像,就是后面加上 upload 参数,并用 -r 参数设置PyPI服务器地址:

$ python setup.py sdist upload -r http://localhost:8080

这样我们就可以通过 http://localhost:8080/simple/ 查看到我们刚才上传到项目包/库。

无认证方式上传.png

认证方式上传

认证方式上传的话,我们需要用到 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项目包/库。

目录下出现了两个版本.png

因为有多个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
>>>

你可能感兴趣的:(搭建、使用与维护私有PyPi仓库)