python包发布到pypi或私有仓库 实践及踩坑 ModuleNotFoundError: No module named 'keyring.util.escape' 等

0.写在开头:

封装我们自己写好的python包然后分享到网络提供给大家使用, 这本来是一个基本操作. 但是之前个人没有主动上传过自己封装的库到pypi, 正好趁这次自己封装简单包提供给大家用的机会, 来尽可能完整的实践了这一过程, 并在过程中踩了一些坑, 这里记录一下踩坑的过程.

1.分享 | 发布 的准备工作

0) 一个包的基础目录结构:
django-jaeger-middleware/
├── django_jaeger_middleware   # 这个包是我们核心代码区, 是我们安装包的主体文件,需要我们首先准备好
│   ├── __init__.py
│   ├── metadata.py
│   └── middleware.py
├── LICENSE               # LICENSE, README.md, setup.py 这些是我们要打包发布的辅助文件
├── README.md
└── setup.py

1 directory, 6 files

1) 创建 setup.py

setup.py 的文件

from setuptools import setup, find_packages

# 这下面几行是做了小小的封装, 可以先跳过直接看 `setup()` 函数部分
MIDDLEWARE_BASE_DIR = os.path.abspath(os.path.dirname(__file__))

meta_file = open(os.path.join(MIDDLEWARE_BASE_DIR, "django_jaeger_middleware", "metadata.py")).read()
md = dict(re.findall(r"__([a-z]+)__\s*=\s*'([^']+)'", meta_file))  # 读取 metadata.py 文件

with open(os.path.join(MIDDLEWARE_BASE_DIR, 'README.md')) as f:
    long_description = f.read()

setup(
    name='django-jaeger-middleware',
    license='MIT',
    version=md['version'],
    description='在这里写对封装的这个包的简单描述',
    long_description=long_description,  # 详细描述,习惯上内容取自`README.md`文件
    long_description_content_type="text/markdown",
    author=md['author'],
    author_email=md['authoremail'],
    url="https://github.com/GalphaXie/django-jaeger-middleware",  # 主页
    download_url='https://github.com/GalphaXie/django-jaeger-middleware',
    packages=find_packages(),
    install_requires=[
        "jaeger_client",  # 封装的包所依赖的基础三方库
    ],
    keywords=['django', 'jaeger', 'jaegertracing'], 
    classifiers=[
        "Framework :: Django",
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',
    zip_safe=False
)

有关字典参数的详细信息,可以参阅官方网站:
1.pypi官方网站对应描述
2.python官方网站对应描述
还有更方便的方式, 就是参考一些成熟的模块的写法进行模仿; 当然,你也可以看看我的这个模块主页

2) 检查setup.py模块是否语法正确

执行 $ python3 setup.py check后, 查看控制台, 当出现:

running check

表示正确. 可以继续进行下一步:

3)补充README.mdLICENSE 内容

提示: 参考其他人的优秀写法, LICENSE 基本找一个官方的三方库复制过来即可

2.根据不同的需求打包|构建模块

1) 需求一: 简单分享, 通过 xxx.tar.gz 传递, 不能使用 pip 安装
# 构建模块
python3 setup.py build  # 会多出一个 build 的目录
# 生成发布压缩包
python3 setup.py sdist   # 会多出一个 dist 目录 和 一个 django_jaeger_middleware.egg-info 目录
注意:要制作哪个版本的模块,就使用哪个版本的解释器执行!

当前的目录结构:

├── build
│   └── lib
│       └── django_jaeger_middleware
│           ├── __init__.py
│           ├── metadata.py
│           └── middleware.py
├── dist
│   └── django-jaeger-middleware-1.0.0.tar.gz
├── django_jaeger_middleware  # 原始目录
│   ├── __init__.py
│   ├── metadata.py
│   └── middleware.py
├── django_jaeger_middleware.egg-info
│   ├── dependency_links.txt
│   ├── not-zip-safe
│   ├── PKG-INFO
│   ├── requires.txt
│   ├── SOURCES.txt
│   └── top_level.txt
├── LICENSE
├── README.md
└── setup.py

6 directories, 16 files

安装模块

  • 1.解压
tar -zxvf 模块名 -C 要解压到的目录
例如: tar -zxvf django-jaeger-middleware-1.0.0.tar.gz 解压到当前目录. 可能你需要类似`site-packages` 这样的目录
  • 2.安装:
    python3 setup.py install

卸载模块

  • 找到模块对应的安装位置, rm -r xxx 即可.
2)需求二: 分享到 pypi 方便更多人使用
1.构建模块

安装setuptoolswheel模块, 如果之前已经安装可以更新到最新, 统一执行官网的

python3 -m pip install --user --upgrade setuptools wheel

  • 1.友情提示: 请对照各自的版本选择python3pythonpython2 , 选择的是那个版本的解释器, 后面编译出来的就是对应的OS + python的版本.
  • 2.友情提示: 全文没有提到关于python 解释器版本的问题, 请根据需要调整解释器版本.
2.生成发布压缩包

python3 setup.py sdist bdist_wheel
正确执行后的目录结构是:

.
├── build
│   ├── bdist.linux-x86_64
│   └── lib
│       └── django_jaeger_middleware
│           ├── __init__.py
│           ├── metadata.py
│           └── middleware.py
├── dist
│   ├── django_jaeger_middleware-1.0.0-py3-none-any.whl
│   └── django-jaeger-middleware-1.0.0.tar.gz
├── django_jaeger_middleware
│   ├── __init__.py
│   ├── metadata.py
│   └── middleware.py
├── django_jaeger_middleware.egg-info
│   ├── dependency_links.txt
│   ├── not-zip-safe
│   ├── PKG-INFO
│   ├── requires.txt
│   ├── SOURCES.txt
│   └── top_level.txt
├── LICENSE
├── README.md
└── setup.py

7 directories, 17 files
3.预发布
  • 1.安装发布需要的工具: twine, 执行
    python3 -m pip install --user --upgrade twine
  • 2.准备发布pypi测试账号, 如果没有需要先去官网注册 注意: 这是测试官网
  • 3.发布测试版本, 执行:
    python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
  • 4.填坑实录: 当然, 我在这里踩了一个坑, 然后给 pypi 提了一个 issue, 可点击这里查看.下面是具体的过程

我在执行改命令行的时候出现报错:ModuleNotFoundError: No module named 'keyring.util.escape' , 我详细看了整个报错.
0.先介绍一下我出错的环境: Ubuntu18.04的系统, python 3.6.9, pip 19.0.1的版本.
1.尝试读一下keyring源码, 简单阅读之后没有发现更好的线索.
2.瞎折腾, 没有结果.
3.看到发布工具是twine 胡乱想到 在 ubuntu 系统下安装有些 win的工具时候是需要, 安装wine工具的, 所以我就怀疑是不是这个发布只能在 win 下面操作, 而不能在 ubuntu下. 虽然这个看起来不那么合理, 但是也只能在 win系统下尝试一下, 死马当做活马医好了. 当然, 这个过程耗费了大量的时间和心情.
4.在win下测试, 我想起来要仔细的查看之前每一个命令的执行过程, 确实没有发现什么问题. 还把过执行过程中的几个 warnning 给依次的处理掉了, 果然这一遍就比较顺利, 执行预发布的过程的时候就顺利进入到输入 pypi 账号密码的环节了. (具体处理的winning有 pip 的升级问题; 某个脚本的环境变量问题,尤其是这个环境变量问题.
5.上面的环境变量问题给了我启示, 我想确认是否是在ubuntu下是我忽略了某些python三方库的脚本没有在全局的python解释器环境中. 遂 重复上面的详细的步骤, 然后观察每一步输出到控制台的结果. 但是, 我并没有发现什么蛛丝马迹.
6.报错bug依然出现. 所以我不得已认真去看谷歌中, 昨天没有认真看的一篇帖子(帖子地址), 在一番迫不得已的耐心寻找下我终于找到了蛛丝马迹. 让我对我安装的 keyrings 库的版本问题产生了合理怀疑, 结合pip3 install --upgrade keyrings.alt 命令, 我做了尝试.

  • 5.几番折腾下来, 我就找到了正确的姿势:
    • 1.python3 -m pip install keyring # 安装

    • 2.正确安装后, 进入python3解释器, 试图导入 import keyring 报相同的错误

    • 3.然后执行:
      python3 -m pip install --upgrade keyrings.alt

    • 4.正确执行后, 进入python3解释器, 试图导入 import keyring , 控制台终于没有再报错;我继续执行 import keyring.util.escape, 又继续报错.

    • 5.然后我就根据上面的操作合理推测, 是不是要单独安装keyring.utilkeyring.util.escape 这两个包. 但是, 安装的时候发现并没有这两个包单独存在于 pypi 仓库. 同时, 我还使用 dir(keyring)dir(keyring.util)来注意观察 keyring 这个包是否有 对应的属性和方法. 发现是: keyring.util 这个属性是存在的.

    • 6.当我再视图查看 是否有keyring.util.escape 的时候, dir 出现了一堆结果, 我就不看了. 继续从原始的上传命令着手 python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/* , 终于这行命令也不在报错了.

4.下载测试
  • 1.当正常上传 到 pypi测试官网 之后, 我们可以进行下载安装,看看是否正确,执行: python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-pkg
  • 2.注意参数--no-deps 是说忽略掉 你要安装的包所需要的其他依赖包. (解释一下这个"坑": 我们自己包目前是分享到pypi的测试服, 而如果我们自己包中依赖了其它的三方库, 这些三方的库不一定在 pypi测试服 上面有对应的安装包, 我们就需要忽略这些报错. 如果不加该参数那么会报找不到依赖包的错误.)
  • 3.当看到下载successful 的时候, 我们可以进入python解释器执行import example, 当导入example-pkg不报No module 即可, 因为有可能报 xxx包 no module 的错误, 忽略即可.
  • 4.也可以参考这里的下载方法.
5.注册pypi正式服账号, 上传包到 正式服.
  • 1.一定要完成注册和认证, 不然后面上传等报错, 大部分都是因为认证不完善或不正确.
  • 2.执行: twine upload dist/* 上传即可, 不需要再指定 url
  • 3.可以前往自己的 pypi 账户进行查看.
3)需求三: 分享到 gitlab等私有仓库, 供内部使用
1.将代码封装的包的代码发布到 gitlab 仓库
  • 1.发布方法和日常提交代码并无二致, 要关注 .gitignore 的写法, 可以参考这里
2.安装和使用
  • 1.一般 gitlab 私有仓库都是加密的, 所以需要账户的身份和权限, 一般需要配置 deploy token 信息.
  • 2.具体命令: pip install -e git+https://{deploy token}@git.ucloudadmin.com/securityhouse/pyservice/django-jaeger-middleware.git#egg=1.0.0
    • 2.1其中{deploy token} 对应的是 name:password , 注意去掉 {}
    • 2.2 egg=tag名,tag需要由最新的master分支创建; 也可对应setup.py中的包名, 我的示例中是 1.0.0
    • 2.3 注意上述安装是默认安装 master分支上的内容, 如果要安装非 master 分支上的内容, 需要将上述命令的#egg=1.0.0部分替换成@你的分支名#egg=包名 . 不易不要漏掉对应的各个符号.
3.docker 中必须配置 deploy token 否则报错

参考资料:

本文例子的URL:

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值