setup.py 真难写
似乎从有 Python 打包以来就有了setuptools这个库,你能搜到的教程,涉及打包发布的,都会让你编写那个可怕的setup.py。不知道谁能完全掌握那个东西的写法,我到现在都还不太会。说几个常用的配置:
指定依赖和可选依赖
setup(
install_requires=["flask", "flask-migrate", "sqlalchemy"],
extras_require={"mysql": ["mysqlclient"], "pgsql": ["psycopg2"]}
)
注意那两个 key 分别是install_requires和extras_require,别写错了。此外,如果你需要根据条件增减依赖的话,不要用
INSTALL_REQUIRES = ["flask"]
if sys.platform == "win32":
INSTALL_REQUIRES.append("pywin32")
setup(install_requires=INSTALL_REQUIRES)
而应该使用Environment Markers
INSTALL_REQUIRES = [
"flask",
"pywin32; sys_platform == 'win32'"
]
setup(install_requires=INSTALL_REQUIRES)
发布可执行程序到/bin下
setup(
entry_points={
"console_scripts": ["mybin=mypackage.main:cli"]
}
)
或者 ini 写法
setup(
entry_points="""[console_scripts]
mybin = mypackage.main:cli
"""
)
任选其一。
包含 data 文件
setup(
include_package_data=True # 从MANIFEST.in中读取配置
)
或者
setup(
package_data={"": ["*.json"]} # 包含所有json文件
)
指定源代码结构,如果你使用的是src/存放包的源码这种项目结构,可以:
setup(
package_dir={"": "src"}
)
打包上传和安装
打包
好了,这个万恶的setup.py我已经写好了,咱要发布 PyPI 了。第一步,打包成可分发的文件:
$ python setup.py sdist bdist_wheel --universal
这条命令会同时生成源代码包(Source Distribution),和二进制包(Binary Distribution)。当然,大部分的 Python 发布包中并不真的包含二进制, 只是沿用了软件工程中的一般叫法。
其中bdist_wheel生成的二进制包是 wheel 格式(需要安装wheel才能打包),--universal的意思是这个二进制包对所有 支持的 Python 版本和 ABI 都适用,「 一处打包,到处使用」,生成的文件名类似:my_package-0.1.0-py3-none-any.whl。
如果你包中有 C 扩展, 也就是打包出来的 wheel 会真的有二进制文件时就不能加这个 flag 了,这时生成的文件名类似:my_package-0.1.0-cp38-cp38-win_amd64.whl。
这个文件名不是乱来的,是要遵循一定规则,下载器能直接从这个文件名获得这个包的基本信息
上传
可能有老的教程,让你直接用python setup.py sdist bdist_wheel register upload打包上传一步到位,这个方式已经过时了不推荐使用。正确的方法应该用twine工具:
$ twine upload dist/*
如果你要把上传放到 CI 里自动执行,最好生成一个 token 来使用,访问 https://pypi.org/manage/accou... 按提示生成一个 token,使用的时候只要用命令指定下用户名和密码:
twine upload --username __token__ --password ${{ secrets.PYPI_TOKEN }} dist/*
安装
把包上传到 PyPI 以后,pip install my-package的时候是怎么安装的呢?
- 访问https://pypi.org/simple/my-pa...,解析所有链接
- 若是 whl 文件,判断是否与当前 Python 版本、ABI、平台适配,加入到候选列表
- 从标签中读取data-requires-python属性,判断是否与当前 Python 版本兼容,加入候选列表
- 若是源代码包,直接加入候选列表
最终在候选列表中优先选择 whl 文件为待安装的包,将包下载到本地,候选包的选择可以由pip install的--only-binary和--no-binary选项控制。
[build-system]
requires = ["setuptools >= 40.8.0", "wheel"]
build-backend = "setuptools.build_meta:__legacy__"
get_requires_for_build_wheel,构建 wheel 需要的依赖列表,这个一般没有特殊要求都是空
- get_requires_for_build_sdist,构建 sdist 需要的依赖列表,同上
- prepare_metadata_for_build_wheel,生成一个 wheel 要用的dist-info/文件夹
- build_wheel,生成 wheel 文件
- build_sdist,生成 sdist 文件
有了这些接口,pip以及其他可能的 frontend 就能从源代码构建一个 wheel 出来。因此,pyproject.toml必须被包含在源代码包中。
有了 PEP 517 的协议规范以后,backend 和 frontend 就能自由组合,不再是非setuptools不可了,实现了 PEP 517 的 backend 有:
以上就是本次分享的所有内容,想要了解更多 python 知识欢迎前往公众号:Python 编程学习圈 ,发送 “J” 即可免费获取,每日干货分享