PEP 423 – 与打包相关的命名约定和方法
- 作者:
- Benoit Bryon <benoit at marmelune.net>
- 讨论至:
- Distutils-SIG 邮件列表
- 状态:
- 推迟
- 类型:
- 信息性
- 主题:
- 打包
- 创建日期:
- 2012年5月24日
- 发布历史:
摘要
本文档涉及
- Python项目名称,
- 正在分发的Python包或模块名称,
- 命名空间包。
它为分发作者提供了指南和方法
PEP 延期
本PEP的进一步审议已被推迟,至少要等到 PEP 426(软件包元数据2.0)及相关更新解决之后。
术语
参考是Python文档中的打包术语。
与其他 PEP 的关系
概述
以下是选择名称时应遵循的指南摘要列表
- 理解并尊重命名空间所有权.
- 如果您的项目与另一个项目或社区相关
- 在主项目文档中搜索约定,因为项目应该组织社区贡献。
- 如果存在,请遵循特定项目或相关社区约定。
- 如果没有约定,请遵循标准命名模式。
- 确保您的项目名称是唯一的,即避免重复
- 确保分发包和模块名称是唯一的,除非您明确希望分发现有包或模块的替代品。对包/模块名称和项目名称使用相同的值是实现此目的的推荐方式。
- 一次只分发一个包或模块,除非您知道自己在做什么。这样可以应用“使用单一名称”规则,从而使名称保持一致。
- 使您的项目易于发现和记住
- 避免深度嵌套。扁平化的东西比嵌套的更容易使用和记住
- 建议使用一到两个命名空间级别,因为它们几乎总是足够的。
- 即使不推荐,三层也实际上是常见的。
- 在大多数情况下,您不需要超过三个级别。
- 遵循PEP 8中包和模块名称的语法。
- 如果您遵循了特定约定,或者您的项目旨在接收社区贡献,请组织社区贡献。
- 如果仍然有疑问,请咨询.
如有疑问,请咨询
如果您阅读本文档后仍感到不确定,请在IRC或邮件列表上咨询Python社区。
顶级命名空间与代码所有权相关
这有助于避免项目名称之间的冲突。
所有权可以是
- 个人。示例:gp.fileupload 由Gael Pasgrimaud拥有和维护。
- 组织。示例
- zest.releaser 由Zest Software拥有和维护。
- Django 由Django Software Foundation拥有和维护。
- 一个团体或社区。示例:sphinx 由Sphinx项目的开发人员维护,而不仅仅是其作者Georg Brandl。
- 与另一个包相关的团体或社区。示例:collective.recaptcha 由其作者David Glick,Groundwire拥有。但“collective”命名空间由Plone社区拥有。
尊重所有权
在使用命名空间之前,请了解其目的。
除非明确授权,否则不要插入您不拥有的命名空间。
例如,不要插入“django.contrib”命名空间,因为它由Django的核心贡献者管理。
项目作者可以定义例外情况。参见下面的组织社区贡献。
此外,此规则适用于非Python项目。
例如,不要使用“apache”作为顶级命名空间:“Apache”是一个现有项目的名称(在“Apache”的情况下,它也是一个商标)。
私有(包括闭源)项目使用命名空间
...因为私有项目由某人拥有。因此,应用所有权规则。
对于内部/客户项目,使用您的公司名称作为命名空间。
此规则适用于闭源项目。
例如,如果您正在为“Python Sport”公司创建一个“climbing”项目:使用“pythonsport.climbing”名称,即使它是闭源的。
个人项目使用命名空间
...因为它们由个人拥有。因此,应用所有权规则。
即使项目具有“内部”或“个人”名称,将其作为开源项目发布也无需羞愧。
如果项目发展到作者希望更改所有权的地步(即项目不再属于个人),请记住重命名项目很容易。
社区拥有的项目可以避免命名空间包
如果您的项目足够通用(即它不是另一个产品或框架的贡献),您可以避免命名空间包。基本条件通常是您的项目由专门从事此项目的团体(即开发团队)拥有。
只有当您确实打算让代码为社区所有时,才使用“共享”命名空间。
例如,sphinx项目属于Sphinx开发团队。没有必要拥有一个只有一个“sphinx.sphinx”项目的“sphinx”命名空间包。
如有疑问,请使用个人/组织命名空间
如果您的项目确实是实验性的,最好的选择是使用个人或组织命名空间
- 它允许项目尽早发布。
- 如果项目被废弃,它不会占用名称。
- 它不会阻碍未来的变化。当项目成熟且没有理由保留个人所有权时,仍然可以重命名项目。
使用单一名称
每个项目只分发一个包(或一个模块),并使用包(或模块)名称作为项目名称。
- 它避免了项目名称与分发包或模块名称之间可能产生的混淆。
- 它使名称保持一致。
- 它是明确的:当看到项目名称时,可以猜测包/模块名称,反之亦然。
- 它还限制了包/模块名称之间的隐式冲突。通过使用单一名称,当您在PyPI上注册项目名称时,您也执行了基本的包/模块名称可用性验证。
例如,pipeline、python-pipeline 和 django-pipeline 都分发了一个名为“pipeline”的包或模块。因此,安装其中两个会导致错误。如果这些分发使用单一名称,则不会发生此问题。
是
- 包名称:“kheops.pyramid”,即
import kheops.pyramid
- 项目名称:“kheops.pyramid”,即
pip install kheops.pyramid
否
- 包名称:“kheops”
- 项目名称:“KheopsPyramid”
注意
由于历史原因,PyPI 包含许多项目和分发包/模块名称不同的分发。
多个包/模块应该很少见
从技术上讲,Python 分发可以提供多个包和/或模块。有关详细信息,请参阅安装脚本参考。
有些分发确实如此。例如,setuptools 和 distribute 都声明了“pkg_resources”、“easy_install”和“site”模块,此外还有各自的“setuptools”和“distribute”包。
将此用例视为例外。在大多数情况下,您不需要此功能。因此,一个分发应该一次只提供一个包或模块。
不同的名称应该很少见
使用单一名称规则的一个显著例外是当您明确需要不同名称时。
例如,Pillow 项目提供了原始 PIL 分发的替代方案。这两个项目都分发一个“PIL”包。
将此用例视为例外。在大多数情况下,您不需要此功能。因此,分发包名称应与项目名称相同。
遵循PEP 8中包和模块名称的语法
PEP 8 适用于 Python 包和模块的名称。
选择令人难忘的名称
项目名称的一件重要事情是它要令人难忘。
例如,celery 不是一个有意义的名称。最初,它不明显是关于消息队列的。但它令人难忘,部分原因是可以用来喂养一个RabbitMQ服务器。
选择有意义的名称
问问自己“我将如何用一句话描述这个名称的用途?”,然后“有人能通过查看名称来猜测吗?”
例如,DateUtils 是一个有意义的名称。它显然是处理日期实用程序的。
当您使用命名空间时,尽量使每个部分都具有意义。
使用打包元数据
将项目名称视为 PyPI 上的唯一标识符
- 重要的是这些标识符保持人类可读。
- 如果这些标识符有意义,那就更好了。
- 但标识符的主要目的不是对项目进行分类或描述。
分类器和关键词元数据用于分发的分类。 摘要和描述元数据用于描述项目。
例如,有一个“Framework :: Twisted”分类器。即使名称相当异构(它们不遵循特定模式),我们仍然可以获得列表。
为了组织社区贡献,关于名称和命名空间的约定很重要,但关于元数据的约定应该更重要。
例如,我们可以在许多地方找到 Plone 小部件
- plone.portlet.*
- collective.portlet.*
- collective.portlets.*
- collective.*.portlets
- 一些与供应商相关的项目,如“quintagroup.portlet.cumulus”
- 甚至名称中没有出现“portlet”模式的项目。
即使 Plone 社区有约定,使用名称来分类分发也是不合适的。通过过滤名称,无法获得提供 Plone 小部件的所有分发的完整列表。但如果所有这些分发都使用“Framework :: Plone”分类器和“portlet”关键字,那将是可能的。
避免深度嵌套
Python之禅说“扁平优于嵌套”。
两层几乎总是足够的
不要在深层嵌套的层次结构中定义所有内容:您最终会得到诸如“pythonsport.common.maps.forest”之类的项目和包。这种类型的名称既冗长又笨重(例如,如果您从包中导入很多内容)。
此外,大型层次结构往往会随着时间的推移而崩溃,因为不同包之间的界限变得模糊不清。
共识是优先使用两层嵌套。
例如,我们有 plone.principalsource
而不是 plone.source.principal
或类似的东西。名称更短,包结构更简单,并且在这里拥有三层嵌套几乎没有任何好处。试图将所有“核心 Plone”源(源是一种词汇表)放入 plone.source.*
命名空间是不切实际的,部分原因是一些源是其他包的一部分,部分原因是因为源已经存在于其他地方。如果我们创建了一个新的命名空间,它从一开始就会被不一致地使用。
是:“pyranha”
是:“pythonsport.climbing”
是:“pythonsport.forestmap”
否:“pythonsport.maps.forest”
所有权只使用一层
不要使用3层来在社区命名空间中设置个人/组织所有权。
例如,让我们考虑
- 您正在插入一个社区命名空间,例如“collective”。
- 您想添加一个更严格的“所有权”级别,以避免社区内部的冲突。
在这种情况下,您最好将最严格的所有权级别作为第一层。
例如,其中“collective”是“gergovie”所属的主要社区命名空间,“vercingetorix”是“gergovie”作者的名字
否:“collective.vercingetorix.gergovie”
是:“vercingetorix.gergovie”
不要使用命名空间层进行分类
请改用打包元数据。
不要使用超过3层
从技术上讲,您可以创建深度嵌套的层次结构。但是,在大多数情况下,您不应该需要它。
注意
即使是命名空间是标准的社区,也不使用超过3层。
在PyPI上注册名称
PyPI 是 Python 社区中分发的中心位置。因此,它也是注册项目和包名称的地方。
有关详细信息,请参阅向包索引注册。
方法
以下方法将帮助您遵循上述指南和约定。
如何检查名称可用性?
在选择项目名称之前,请确保它尚未在以下位置注册
- PyPI
- 就是这样。PyPI是唯一的官方场所。
例如,您也可以在各种位置(如流行的代码托管服务)进行检查,但请记住,PyPI是您在Python社区中可以**注册**名称的唯一地方。
这就是为什么在PyPI上注册名称很重要的原因。
还要确保已分发包或模块的名称尚未注册
- 在Python 标准库中。
- 在
PyPI
上的项目内部。目前没有相关的辅助工具。请注意,遵循使用单一名称规则的项目越多,验证就越容易。 - 您可以咨询社区。
使用单一名称规则也有助于您避免与包名称冲突:如果项目名称可用,那么包名称也很可能可用。
如何重命名项目?
重命名项目是可能的,但请记住这会造成一些混淆。因此,请特别注意 README 和文档,以便用户理解发生了什么。
- 首先,不要从 PyPI 中删除旧的分发。因为有些用户可能正在使用它们。
- 复制旧项目,然后更改名称(项目和包/模块)。至少要注意
- 打包文件,
- 包含源文件的文件夹名称,
- 文档,包括 README,
- 代码中的导入语句。
- 在 setup.cfg 文件中为新分发分配
Obsoletes-Dist
元数据。请参阅 PEP 345 关于 Obsolete-Dist 和 setup.cfg 规范。 - 发布重命名项目的新版本,然后发布它。
- 编辑旧项目
- 添加对新项目的依赖,
- 删除除打包内容之外的所有内容,
- 在安装脚本中添加
Development Status :: 7 - Inactive
分类器, - 发布新版本。
因此,旧包的用户
- 可以继续使用已弃用版本的旧分发,
- 可以升级到旧分发的最新版本,该版本是空的……
- ...并自动下载新的分发作为旧分发的依赖项。
发现旧项目的用户会看到它处于非活动状态。
改进PyPI上重命名项目的处理
如果许多项目都遵循重命名指南,那么许多旧的分发将具有以下特征
Development Status :: 7 - Inactive
分类器。- 最新版本为空,除了打包内容。
- 最新版本“重定向”到另一个分发。例如,它对重命名项目具有单一依赖关系。
- 在较新的分发中被引用为
Obsoletes-Dist
。
因此,将能够检测重命名的项目并提高 PyPI 的可读性。这样用户就可以专注于活动分发。但目前不需要此功能。没有紧迫性。本文档中将不涉及此内容。
如何将命名指南应用于现有项目?
现有项目没有义务重命名。出于显而易见的原因,选择权留给项目作者和维护者。
但是,邀请项目作者
- 至少,说明当前命名。
- 然后规划并推广迁移。
- 可选地实际重命名现有项目或分发的包/模块。
关于当前命名的说明
首先,重要的是您要说明当前的选择
- 问问自己“我为什么选择当前名称?”,然后记录下来。
- 如果与本文档中提供的指南有差异,您应该告知您的用户。
- 如果可能,请在项目的错误跟踪器中创建问题,至少作为记录。然后您可以稍后解决它们,或者可能将其标记为“wontfix”。
旨在接收社区贡献的项目也应该组织社区贡献。
促进迁移
每个 Python 开发者都应尽可能迁移,或在其各自的社区中推广迁移。
将这些指南应用于您的项目,然后社区就会看到它是安全的。
特别是,“领导者”,如流行项目的作者,具有影响力,他们拥有权力,因此对社区负有责任。
将这些指南应用于流行项目,然后社区也会采纳这些约定。
项目应在发布新(主要)版本时促进迁移,特别是如果此版本引入了对 Python 3.x、新标准库的打包或命名空间包的支持。
机会
随着 Python 3.3 的开发
- 许多项目不兼容 Python 3.x。这包括“大型”产品或框架。这意味着许多项目将不得不进行迁移以支持 Python 3.x。
- 打包(又称 distutils2)正在启动。发布后,项目将被邀请迁移并使用新的打包。
- PEP 420 为 Python 带来了命名空间包的官方支持。
这意味着大多数活跃项目将在未来一年内迁移以支持 Python 3.x、新打包或新命名空间包。
这样的机会是独一无二的,不会很快再次出现!所以让我们尽快(即现在)引入和推广命名约定。
参考资料
额外背景
- Martin Aspeli 关于名称的文章。本文档的某些部分引用了这篇文章。
- 开发中的官方打包文档.
- 包装徒步指南,其中有一个“命名规范”的空占位符。
参考文献和脚注
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0423.rst