关于python:2022年你应该知道的Python打包指南

2次阅读

共计 3254 个字符,预计需要花费 9 分钟才能阅读完成。

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 选项管制。

当初筹备装置了,如果待装置的是 whl,那就非常简单,间接解压(whl 文件是一种 zip 格局),放到目标目录即可,解压后产生的文件除了代码或二进制以外,还会蕴含一个 my_package-0.1.0.dist-info/ 目录,蕴含这个包的元数据信息,比方有哪些文件、文件 hash 值、entry_points 等等。

如果待装置的文件是源代码包,那么须要把这个压缩包解压到一个长期目录,依据包指定的形式编译构建,生成 whl 文件,再用 whl 装置同样的办法放到目标目录中。而这个指定的编译形式,在 PEP 517 提案之前,是调用 python setup.py install 命令。在 PEP 517 公布之后,则由 PEP 517 的 build backend 管制。

setuptools 不再是惟一的抉择
PEP 517 的内容简略来说,就是在我的项目根目录下的 pyproject.toml 定义了两个非凡属性(注:其实还有第三个属性 backend-path,当你的 backend 是在本地时应用。):

[build-system]
requires = ["setuptools >= 40.8.0", "wheel"]
build-backend = "setuptools.build_meta:__legacy__"

下面这个就是 setuptools 的 PEP 517 的配置,这样能够让老的我的项目,能间接用 PEP 517 的形式构建。如果你的我的项目中并没有 pyproject.toml 文件,pip 能主动填充为此缺省配置。其中 requires 意为这个 backend 依赖的包列表,build-backend 则为 backend 的具体位置。这个 backend 须要实现几个约定的接口:

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 有:

  • Poetry-core
  • Flit-core
  • pdm-pep517

所以我能够不必写 setup.py 了
setup.py 作为一个元数据的定义格局是有问题的:
必须由 Python 运行,无奈动态解析
因为第 1 点,有注入恶意代码的操作可行性
所以须要指定一个元数据的配置格局,这个格局标准最近也定下来了,它就是 PEP 621,也是应用 pyproject.toml 来定义的。而且,PDM 曾经反对这个配置格局了,仅此一家。

以上就是本次分享的所有内容,想要理解更多 python 常识欢送返回公众号:Python 编程学习圈,发送“J”即可收费获取,每日干货分享

正文完
 0