PEP 632 – 废弃 distutils 模块
- 作者:
- Steve Dower <steve.dower at python.org>
- 讨论至:
- Discourse 帖子
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 创建日期:
- 2020年9月3日
- Python 版本:
- 3.10
- 发布历史:
- 2020年9月3日,2021年1月22日
- 决议:
- Python-Dev 帖子
摘要
distutils 模块 [1] 长期以来一直建议使用 setuptools 包 [2]。Setuptools 最近集成了 distutils 的完整副本,并且不再依赖于标准库 [3]。Pip 在安装包时已经默默地用 setuptools 替换 distutils 很长时间了,并且 distutils 的文档自2014年(或更早)就声明其正在逐步淘汰。现在是时候将其从标准库中移除了。
动机
distutils [1] 是一个在很大程度上未被文档化和未被维护的实用程序集合,用于打包和分发 Python 包,包括编译本地扩展模块。它定义了一个描述 Python 分发的配置格式,并提供了将源代码目录转换为源代码分发和某些形式的二进制分发的工具。由于它在标准库中的位置,许多更新只能随主要版本发布,并且用户无法依赖于特定的修复可用。
setuptools [2] 是一个基于 distutils 的、文档更完善且维护良好的增强工具。虽然它提供了非常相似的功能,但它能更好地支持早期 Python 版本的用户,并且能更快地响应错误报告。setuptools 中已经存在许多特定于平台的增强功能,而这些功能尚未添加到 distutils 中,并且 distutils 文档中长期以来一直建议优先使用 setuptools。
历史上,setuptools 通过子类化和猴子补丁来扩展 distutils,但现在已经复制了底层代码。[3] 因此,对 distutils 的倒数第二个主要依赖已经消失,没有必要将其保留在标准库中。
对 distutils 的最终依赖是 CPython 本身,它使用 distutils 来构建标准库中的原生扩展模块(Windows 除外)。由于这是 CPython 构建时的依赖,因此即使 distutils 不属于标准库的一部分,也可以继续将其用于这个特定情况。
废弃和移除将明确指出问题应在 setuptools 项目中修复,并将减少错误报告的来源和不必要的测试维护。它还将有助于促进替代构建后端的发展,现在由于 PEP 517,这些后端可以更容易地得到支持。
规范
在 Python 3.10 和 3.11 中,distutils 将被正式标记为已废弃。届时所有已知问题都将关闭。import distutils 将引发废弃警告。可能仍会修复被视为阻止发布的重大问题,但不会添加对新工具或平台的支持。
在 Python 3.10 和 3.11 期间,标准库中对 distutils 的使用可能会改为使用其他 API。
在 Python 3.12 中,distutils 将不再通过 make install 或任何第一方分发进行安装。第三方重新分发者不应再将 distutils 包含在其捆绑包或仓库中。
本 PEP 未就迁移当前使用 distutils 的 CPython 构建过程的某些部分做出具体说明。根据贡献情况,此迁移可能随时发生。
Python 3.12 启动后,并且当 CPython 构建过程不再依赖标准库中的 distutils 时,整个 Lib/distutils 目录和 Lib/test/test_distutils.py 文件将从仓库中删除。
对 distutils 的其他引用将被清理。截至 Python 3.9 的初始发布,以下模块在代码或注释中包含引用:
- Lib/ctypes/util.py
- Lib/site.py
- Lib/sysconfig.py
- Lib/_aix_support.py
- Lib/_bootsubprocess.py
- Lib/_osx_support.py
- Modules/_decimal/tests/formathelper.py
CPython 中的以下工具也引用了 distutils。请注意,这些工具都不会随 CPython 安装
- PC/layout(引用将被移除)
- Tools/msi(引用将被移除)
- Tools/peg_generator(将被修改以适应不同的构建工具)
- Tools/test2to3(示例项目将被移除)
由于 distutils 代码已包含在 setuptools 中,因此无需以任何其他形式重新发布它。需要访问此功能的用户应使用 setuptools 或其他构建后端。
向后兼容性
从 Python 3.12 开始,导入 distutils 的代码将不再起作用。
建议的迁移路径是使用 setuptools 中等效(但不完全相同)的导入(参见 [5]),或者迁移到替代的构建后端(参见 PEP 517)。
setuptools 中已存在代码,可透明地将使用 distutils 的 setup.py 文件切换到其等效文件,因此已知大多数正常工作的构建脚本已经可以与 setuptools 配合使用。此类脚本可能需要更新其导入语句。有关具体迁移建议,请查阅 setuptools 文档。[5]
一些项目对 distutils 使用了不同的补丁集,特别是 numpy.distutils。[6] 我们已通知已知这样做过的项目。
许多构建脚本使用自定义命令或狭窄范围的补丁。由于这些包已经受到 setuptools 覆盖 distutils 的影响,我们预计 distutils 的移除将导致最小程度的中断。脚本可能仍然需要更新以避免导入 distutils。
参考实现
setuptools 版本 48 包含 distutils 的完整副本,因此不再依赖标准库的副本。他们所面临的大多数实现问题都是由于 distutils 在标准库中的持续存在造成的,因此移除将提高其实现的稳定性。
目前还没有从标准库中移除 distutils 的参考实现,也没有 CPython 原生模块构建在不依赖标准库中 distutils 副本的情况下的实现。
迁移建议
注意
本节提出了一些替代方案,用于取代本 PEP 正式废弃的流行功能。本节内容在编写时是最新的,但并未持续更新。
对于这些模块或类型,setuptools 是最佳替代品
distutils.ccompilerdistutils.cmd.Commanddistutils.commanddistutils.configdistutils.core.Distributiondistutils.errors
对于这些模块或类型,请使用指定的标准定义的 Python Packaging Authority 包
distutils.version— 使用packaging包
对于这些模块或函数,请使用所示的标准库模块
distutils.fancy_getopt— 使用argparse模块distutils.spawn.find_executable— 使用shutil.which函数distutils.spawn.spawn— 使用subprocess.run函数distutils.sysconfig— 使用sysconfig模块distutils.util.get_platform— 使用platform模块
对于这些函数以及此处未提及的任何其他函数,您需要自行重新实现其功能。旧版文档可在 https://docs.pythonlang.cn/3.9/distutils/apiref.html 找到
distutils.dir_util.create_treedistutils.util.change_rootdistutils.util.strtobool
被拒绝的想法
废弃但不删除
这种方法的主要问题是 distutils 最常由于平台差异而中断,这意味着如果没有维护,它将与任何 Python 版本不同步而停止工作。这使得库无法可靠地检测它们何时会停止工作。
相比之下,本 PEP 提出了一个具体的日期,提前明确告知 distutils 何时将停止工作,并承诺在此之前不会破坏 API。这为维护者提供了一个可预测的时间表,确保任何中断都发生在用户已经预期行为改变的时候,并提供了一个可靠的检测机制(具体而言,import distutils 会引发错误)。
最后,只要 distutils 以任何形式保留在标准库中,它就会干扰提供垫片或替代品的第三方软件包,包括 setuptools。在已知版本完全移除该软件包使得第三方能够安全地使用替代品。
只废弃类似于 setuptools 的功能
这个建议假定存在一个志愿者来维护剩余的部分,但这并非事实。它还暗示任何人知道哪些功能应该保留,而正如讨论中所示,这根本不清楚。
distutils 中的大多数辅助函数已经有受支持的(且已改进的)替代方案,通常在标准库中,并且在不破坏兼容性的前提下,对旧版本几乎无法进行任何操作。(而且任何需要维护者更新其代码的破坏,本质上都等同于要求他们导入不同的函数。)
上一节的最后一点也适用于这里。
参考资料
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源: https://github.com/python/peps/blob/main/peps/pep-0632.rst
最后修改时间: 2025-02-01 08:55:40 GMT