Python标准库入口点注册机制及全量查询方法问询
一、第三方包注册Entry Points的常规操作
先明确第三方包注册entry points的两种主流方式:
- 若使用setuptools/distutils打包,直接在
setup.py的setuptools.setup()函数中指定entry_points参数,示例如下:
setuptools.setup( # 其他配置参数... entry_points={ "setuptools.finalize_distribution_options": [ "parent_finalize = setuptools.dist:_Distribution.finalize_options", "features = setuptools.dist:Distribution._finalize_feature_opts", "keywords = setuptools.dist:Distribution._finalize_setup_keywords", "2to3_doctests = setuptools.dist:Distribution._finalize_2to3_doctests", ], } )
- 若不依赖setuptools/distutils(比如用Poetry等工具),则在
pyproject.toml中配置,格式示例:
[project.entry-points."setuptools.finalize_distribution_options"] parent_finalize = "setuptools.dist:_Distribution.finalize_options" features = "setuptools.dist:Distribution._finalize_feature_opts"
二、标准库包的Entry Points从何而来?
你提到的distutils.setup_keywords组下的那些entry points,并非标准库原生注册的:准确来说,distutils本身并没有这些配置,是setuptools在安装时向distutils的entry points组注入了这些扩展项。
原因很简单——setuptools本质是distutils的增强版,它通过entry points机制来扩展distutils的功能,比如给setup.py新增关键字参数并提供对应的校验逻辑。这些entry points都定义在setuptools自身的打包配置里(也就是setuptools自己的setup.py或pyproject.toml中),当你完成setuptools安装后,这些entry points就会被注册到系统的包元数据中。
至于标准库本身,其实很少直接使用entry points机制——因为entry points主要是为第三方包提供扩展入口设计的,标准库模块大多是独立实现,不需要通过这种方式来扩展功能。
三、如何列出所有已注册的Entry Points(无需指定组名)
如果你想遍历所有已注册的entry points,不管所属分组,有两种实用方法:
方法1:使用setuptools的pkg_resources(兼容旧版本Python)
pkg_resources是setuptools自带的模块,大多数Python环境默认都包含:
import pkg_resources # 获取所有entry points分组 all_groups = pkg_resources.get_entry_map().keys() for group in all_groups: print(f"\n=== Entry Point Group: {group} ===") # 遍历当前分组下的所有entry points for ep in pkg_resources.iter_entry_points(group=group): # 格式化输出entry point的名称与指向路径 attr_str = f":{ep.attrs[0]}" if ep.attrs else "" print(f"{ep.name} = {ep.module_name}{attr_str}")
方法2:使用标准库的importlib.metadata(Python 3.8+推荐)
从Python 3.8开始,标准库引入了importlib.metadata模块,无需依赖setuptools就能处理包元数据:
from importlib.metadata import entry_points # 获取所有分组的entry points all_entry_points = entry_points() for group, eps in all_entry_points.items(): print(f"\n=== Entry Point Group: {group} ===") for ep in eps: print(f"{ep.name} = {ep.value}")
另外,你也可以直接查看各个包安装目录下的*.dist-info或*.egg-info文件夹里的entry_points.txt文件,这些文件存储了该包注册的所有entry points的原始信息。
内容的提问来源于stack exchange,提问作者con-f-use

