PEP 262 – 已安装 Python 包的数据库
- 作者:
- A.M. Kuchling <amk at amk.ca>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 主题:
- 打包
- 创建:
- 2001 年 7 月 8 日
- 历史记录:
- 2002 年 3 月 27 日
简介
此 PEP 描述了一种用于存储系统上已安装的 Python 软件的数据库的格式。
(在本文件中,“发行版”一词是指一起开发和分发的代码集。一个“发行版”与 Red Hat 或 Debian 包相同,但“包”一词在 Python 术语中已经有含义,指“包含 __init__.py
文件的目录”。)
要求
我们需要一种方法来确定系统上安装了哪些发行版以及这些发行版的版本。我们希望提供类似于 CPAN、APT 或 RPM 的功能。需要支持的用例包括
- 系统上是否安装了发行版 X?
- 安装了哪个版本的 X 发行版?
- 在哪里可以找到 X 发行版的最新版本?(这可以定义为“用户可以去寻找下载链接的首页”,或“程序可以找到最新版本的地址”?可能两种都应该支持。)
- X 发行版将哪些文件安装到我的系统上?
- x/y/z.py 文件来自哪个发行版?
- 有人在本地修改了 x/y/z.py 文件吗?
- 此软件还需要哪些其他发行版?
- 此发行版提供了哪些 Python 模块?
数据库位置
数据库位于 <prefix>/lib/python<version>/install-db/ 下的一组文件中。在整个 PEP 中,这个位置将被称为 INSTALLDB。
数据库的结构故意保持简单;此目录或其子目录(如果有)中的每个文件都描述一个单独的发行版。Python 软件的二进制打包(如 RPM)可以通过简单地将相应的文件安装到 INSTALLDB 目录来更新 Python 的数据库。
扫描子目录的原因是,如果数据库目录包含太多条目,我们可以迁移到基于目录的索引方案。例如,这将使我们能够透明地从 INSTALLDB/Numeric 切换到 INSTALLDB/N/Nu/Numeric 或类似的哈希方案。
数据库内容
INSTALLDB 或其子目录中的每个文件都描述一个单独的发行版,并且具有以下内容
初始行列出此文件中的部分,用空格分隔。目前这将始终是“PKG-INFO FILES REQUIRES PROVIDES”。这是为了将来扩展;如果我们添加一个新部分,例如列出文档文件,那么我们将在内容中添加一个 DOCS 部分并列出它。部分总是用空行分隔。
使用 Distutils 进行安装的发行版应该自动更新数据库。自行安装的发行版必须使用数据库的 API 手动添加或更新自己的条目。像 RPM 或 pkgadd 这样的系统包管理器可以直接在 INSTALLDB 目录中创建新文件。
文件的每个部分用于不同的目的。
PKG-INFO 部分
一组初始的 RFC 822 标头,其中包含文件的发行版信息,如 PEP 241,“Python 软件包的元数据”中所述。
FILES 部分
发行版安装的每个文件的条目。生成的 .pyc 和 .pyo 文件以及发行版安装的原始 .py 文件都列在这个列表中;它们的校验和不会存储或检查,不过。
每个文件的条目都是一个以制表符分隔的单行,包含以下字段
- 文件在系统上安装的完整路径。
- 文件的大小
- 文件的权限。在 Windows 上,此字段将始终为“unknown”
- 文件的拥有者和组,用制表符分隔。在 Windows 上,这两个字段都将为“unknown”。
- 文件的 SHA1 散列,以十六进制编码。对于生成的 *。pyc 文件,此字段必须包含字符串“ - ”,表示不应该验证文件的校验和。
REQUIRES 部分
此部分是字符串列表,表示此模块发行版正常运行所需的软件服务。此列表包括发行版名称(“python-stdlib”)和模块名称(“rfc822”、“htmllib”、“email”、“email.Charset”)。它将通过 distutils.core.setup()
函数的额外“requires”参数指定。例如
setup(..., requires=['xml.utils.iso8601',
最终可能会有自动化工具浏览所有代码并生成一个需求列表,但这些工具不太可能处理所有可能的案例;手动指定需求的方法将始终是必要的。
PROVIDES 部分
此部分是字符串列表,表示已安装发行版提供的软件服务。此列表包括发行版名称(“python-stdlib”)和模块名称(“rfc822”、“htmllib”、“email”、“email.Charset”)。
XXX 应该列出文件吗?例如 $PREFIX/lib/color-table.txt,以获取数据文件、必需的脚本等。
最终可能会有一个选项,让模块开发人员可以将自己的字符串添加到此部分中。例如,您可以在此部分中添加“XML 解析器”,然后其他模块发行版就可以将“XML 解析器”列为其依赖项之一,以表明可以使用多个不同的 XML 解析器。目前还不支持此功能,因为它引发了太多问题:我们需要一个合法的字符串的中心注册表,还是让用户随便输入任何内容?等等...
API 说明
只有一个基本类,InstallationDatabase。它的代码位于 distutils/install_db.py 中。(XXX 有没有关于标准库中备用位置或备用模块名称的建议?)
InstallationDatabase 返回 Distribution 实例,其中包含有关已安装发行版的所有信息。
XXX Distribution 中的几个字段与 distutils.dist.Distribution 中的字段重复。也许应该将它们分解到此处提出的 Distribution 类中,但这可以以向后兼容的方式完成吗?
InstallationDatabase 具有以下接口
class InstallationDatabase:
def __init__ (self, path=None):
"""InstallationDatabase(path:string)
Read the installation database rooted at the specified path.
If path is None, INSTALLDB is used as the default.
"""
def get_distribution (self, distribution_name):
"""get_distribution(distribution_name:string) : Distribution
Get the object corresponding to a single distribution.
"""
def list_distributions (self):
"""list_distributions() : [Distribution]
Return a list of all distributions installed on the system,
enumerated in no particular order.
"""
def find_distribution (self, path):
"""find_file(path:string) : Distribution
Search and return the distribution containing the file 'path'.
Returns None if the file doesn't belong to any distribution
that the InstallationDatabase knows about.
XXX should this work for directories?
"""
class Distribution:
"""Instance attributes:
name : string
Distribution name
files : {string : (size:int, perms:int, owner:string, group:string,
digest:string)}
Dictionary mapping the path of a file installed by this distribution
to information about the file.
The following fields all come from PEP 241.
version : distutils.version.Version
Version of this distribution
platform : [string]
summary : string
description : string
keywords : string
home_page : string
author : string
author_email : string
license : string
"""
def add_file (self, path):
"""add_file(path:string):None
Record the size, ownership, &c., information for an installed file.
XXX as written, this would stat() the file. Should the size/perms/
checksum all be provided as parameters to this method instead?
"""
def has_file (self, path):
"""has_file(path:string) : Boolean
Returns true if the specified path belongs to a file in this
distribution.
"""
def check_file (self, path):
"""check_file(path:string) : Boolean
Checks whether the file's size, checksum, and ownership match,
returning true if they do.
"""
交付成果
数据库 API 的说明,将添加到此 PEP 中。
Distutils 的补丁,用于 1)实现 InstallationDatabase 类,2)在安装新发行版时更新数据库。3)添加一个简单的包管理工具,功能将添加到此 PEP 中。(或者应该单独创建一个 PEP 吗?)请参阅 [2] 获取当前的补丁。
未解决的问题
PJE 建议安装数据库“可能存在于 sys.path 中的每个目录中,其内容按 sys.path 顺序合并。这将允许主目录或其他备用位置的安装正常工作,并简化 distutils 安装命令写入文件的过程。” 非常棒的功能:这确实意味着包管理器工具可以考虑用户私自安装的 Python 包。
AMK 疑惑:如果告诉 setup.py 将包安装到 sys.path 上不存在的目录中,会发生什么?它会在被告知写入的目录中写入 install-db 目录,还是什么都不做?
包数据库文件本身是否应该包含在文件列表中?(PJE 认为应该,但它当然不能包含它自己的校验和。AMK 无法想到包含 DB 文件很重要的用例。)
PJE 疑惑关于在安装任何其他文件之前首先写入包 DB 文件,以便可以撤销失败的部分安装,并将其识别为已损坏。此 PEP 可能需要指定一些算法来识别这种情况。
我们应该保证安装数据库的格式在不同的 Python 版本之间保持兼容,还是可以随意更改?我们可能需要保证兼容性。
被拒绝的建议
可以使用一个大型文本文件或任何 dbm 文件,而不是每个发行版使用一个文本文件。这被拒绝的原因有几个。首先,性能可能不是一个非常紧迫的问题,因为数据库只在安装或删除软件时使用,这是一个相对不频繁的任务。可扩展性也不太可能成为问题,因为人们可能安装了数百个 Python 包,但数千或数万个 Python 包似乎不太可能。最后,单个文本文件与 RPM 或 DPKG 等安装程序兼容,因为二进制打包程序可以将新的数据库文件放到数据库目录中。如果使用一个大型文本文件或二进制文件,则 Python 数据库必须通过运行后安装脚本进行更新。
在 Windows 上,不会存储文件的权限和拥有者/组。Windows 实际上支持所有权和访问权限,但读取和设置它们需要 win32all 扩展,并且它们不存在于 Windows 的基本 Python 安装程序中。
参考资料
[1] Michael Muller 的补丁(大约在 1999 年 12 月 28 日发布到 Distutils-SIG)生成了一个已安装文件列表。
致谢
此 PEP 的想法最初来自 Greg Ward、Fred L. Drake Jr.、Thomas Heller、Mats Wichmann、Phillip J. Eby 等人的帖子。
Distutils SIG 的读者建议对此文档进行很多更改和重写。
版权
此文档已归入公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0262.rst
最后修改时间:2023-09-09 17:39:29 GMT