# https://github.com/beanbaginc/python-registries 项目说明书

生成时间：2026-06-14 16:20:37 UTC

## 目录

- [Overview & Core Concepts](#page-1)
- [Architecture & Internal Design](#page-2)
- [API Reference & Usage Patterns](#page-3)
- [Error Handling, Extensibility & Operations](#page-4)

<a id='page-1'></a>

## Overview & Core Concepts

### 相关页面

相关主题：[Architecture & Internal Design](#page-2), [API Reference & Usage Patterns](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/beanbaginc/python-registries/blob/main/README.md)
- [registries/__init__.py](https://github.com/beanbaginc/python-registries/blob/main/registries/__init__.py)
- [registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py)
- [registries/items.py](https://github.com/beanbaginc/python-registries/blob/main/registries/items.py)
- [registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)
- [registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)
- [doc-requirements.txt](https://github.com/beanbaginc/python-registries/blob/main/doc-requirements.txt)
- [dev-requirements.txt](https://github.com/beanbaginc/python-registries/blob/main/dev-requirements.txt)
</details>

# Overview & Core Concepts

## 项目定位与设计目标

`python-registries`（PyPI 包名 `registries`，版本 `1.0.1 alpha 0`）是一个用于管理"多实现集合"的 Python 库，专为需要通过抽象接口对接多种后端实现的场景而设计 资料来源：[README.md:1-15]()。该库源自 [Review Board](https://www.reviewboard.org) 团队的工程实践，旨在为插件、扩展、子命令分发、文件格式解析等多种用例提供统一的注册中心 资料来源：[README.md:17-25]()。

库的设计目标集中在以下几点：

- **动态注册与注销**：允许运行时动态加入或移除条目。
- **基于属性的灵活查找**：通过 `lookup_attrs` 声明的字段作为主键。
- **线程安全**：内部使用 `RLock` 保证并发场景下的一致性 资料来源：[registries/registry.py:115-130]()。
- **可扩展钩子**：在注册、注销、初始化、复位等生命周期阶段提供回调点。
- **类型提示支持**：基于 `Generic[RegistryItemType]` 与 `TypeVar`，便于 IDE 与静态检查 资料来源：[registries/items.py:12-18]()。

## 核心组件

包对外仅暴露三个注册表类与若干版本工具函数 资料来源：[registries/__init__.py:22-45]()：

| 类 | 职责 | 关键扩展点 |
|---|---|---|
| `Registry` | 通用注册表，支持多属性查找、动态注册 | `get_defaults`、`lookup_attrs`、`on_item_registered` |
| `OrderedRegistry` | 在 `Registry` 基础上保留注册顺序 | 通过 `id(item)` 与 `_key_order` 列表维护插入次序 |
| `EntryPointRegistry` | 基于 [Python Entry Points](https://packaging.python.org/en/latest/specifications/entry-points/) 的注册表 | 通过 `entry_points()` 自动发现并加载 |

三者的关系可以用如下示意图表示：

```mermaid
classDiagram
    class Registry~T~ {
        +lookup_attrs: tuple
        +state: RegistryState
        +register(item)
        +unregister(item)
        +get(attr)
        +get_or_none(attr)
    }
    class OrderedRegistry~T~ {
        +_by_id: dict
        +_key_order: list
        +on_item_registered(item)
    }
    class EntryPointRegistry~T~ {
        +entry_point_group: str
        +populate()
        +_value_from_entry_point(ep)
    }
    Registry~T~ <|-- OrderedRegistry~T~
    Registry~T~ <|-- EntryPointRegistry~T~
```

## 注册表状态机与生命周期

`Registry` 实例在运行时会经历三种状态，由枚举 `RegistryState` 描述 资料来源：[registries/registry.py:75-90]()：

- **PENDING**：对象刚创建，尚未加载任何默认条目。
- **POPULATING**：正在执行 `populate()`（一般由 `__init__` 隐式触发），将 `get_defaults()` 返回的条目批量入库。
- **READY**：默认条目全部就绪，可以对外提供 `get()`/`get_or_none()` 等查询服务。

```mermaid
stateDiagram-v2
    [*] --> PENDING : __init__()
    PENDING --> POPULATING : populate() / get_defaults()
    POPULATING --> READY : 默认条目注册完成
    READY --> POPULATING : reset() 重新填充
    READY --> [*]
```

子类可以重写 `on_register`、`on_unregister`、`on_populated`、`on_reset` 等钩子，把注册事件桥接到日志、审计、依赖注入等外部系统 资料来源：[README.md:60-70]()。`OrderedRegistry.on_item_registered` 即重写了该钩子，以在 `_key_order` 末尾追加条目 ID 资料来源：[registries/registry.py:330-355]()。

## 错误体系与扩展点

所有注册表相关异常继承自 `BaseRegistryError`，其核心字段是 `message_template`（基于 `%` 格式化字符串） 资料来源：[registries/errors.py:38-52]()。子类按功能分为四族：

- **属性错误**：`UnsupportedRegistryAttributeError`，当 `lookup_attrs` 不包含查询键时抛出。
- **查找错误**：`ItemNotFoundLookupError`，查询不到目标条目时抛出。
- **注册错误**：`RegistrationConflictError`（重复条目冲突）、`InvalidItemRegistrationError`（缺少 `lookup_attrs` 字段）。
- **注销错误**：`AttrNotFoundUnregistrationError`、`ItemNotFoundUnregistrationError`。

每个错误类都可以被注册表子类通过类变量替换，从而输出符合业务语义的提示信息，例如 `unsupported_registry_attr_error_cls`、`item_not_found_lookup_error_cls` 等 资料来源：[registries/registry.py:95-115]()。

## 用法速览

最小化使用方式遵循"定义基类 → 定义注册表 → 初始化 → 注册/查找"的四步流程 资料来源：[README.md:84-110]()：

1. 声明被注册对象的共同基类（类或任意可哈希对象）。
2. 通过继承 `Registry[T]` 声明 `lookup_attrs`，并实现 `get_defaults()` 返回默认条目。
3. 调用构造函数后，注册表自动进入 `POPULATING` 并填充默认条目。
4. 运行时通过 `registry.register(item)` / `registry.get(attr=value)` 与外部交互。

## 开发与文档

- **测试依赖**：`kgb~=7.3`（函数间谍库）与 `pytest` 资料来源：[dev-requirements.txt:1-2]()。
- **文档依赖**：`beanbag-docutils~=2.3`、`furo`、`sphinx-copybutton`、`sphinx~=7.2.0` 资料来源：[doc-requirements.txt:1-4]()。

## See Also

> **社区关注点**：1.0 版本的发布说明强调"插件系统、工厂方法、多种文件格式 / API payload 的统一管理"是该库的核心动机，读者在设计抽象接口与后端分发时可直接复用该模式。

---

<a id='page-2'></a>

## Architecture & Internal Design

### 相关页面

相关主题：[Overview & Core Concepts](#page-1), [API Reference & Usage Patterns](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)
- [registries/items.py](https://github.com/beanbaginc/python-registries/blob/main/registries/items.py)
- [registries/__init__.py](https://github.com/beanbaginc/python-registries/blob/main/registries/__init__.py)
- [registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)
- [registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py)
</details>

# 架构与内部设计

## 概述

`python-registries` 是一个面向"注册中心模式"（Registry Pattern）的 Python 库，旨在为多实现、多后端、多插件的可扩展应用提供统一的注册、查找、迭代与移除能力。库的核心设计围绕着**通用注册中心基类** `Registry[T]` 展开，并在此之上派生出**保序注册中心** `OrderedRegistry` 与**基于 Python Entry Points 的注册中心** `EntryPointRegistry`。所有公开类型在 [registries/__init__.py](https://github.com/beanbaginc/python-registries/blob/main/registries/__init__.py) 中通过转发导入暴露给调用方，便于使用者按需引用。

库版本号遵循 `SemVer` 规范，定义在 [registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py) 的 `VERSION` 元组中，截至 1.0.1 alpha 阶段，模块仍处于发布前的迭代周期。

## 类层次结构

整个库使用泛型 + 继承的方式构建，三类注册中心共享同一套核心逻辑，仅在保序、Entry Point 解析两个维度上进行扩展：

```mermaid
classDiagram
    class Registry~T~ {
        +lookup_attrs: tuple
        +state: RegistryState
        +register(item)
        +unregister(item)
        +get(...)
        +populate()
        +reset()
    }
    class OrderedRegistry~T~ {
        +_by_id: dict
        +_key_order: list
        +on_item_registered(item)
        +on_item_unregistered(item)
    }
    class EntryPointRegistry~T~ {
        +entry_point_group: str
        +populate()
        +_value_from_entry_point(ep)
    }
    Registry <|-- OrderedRegistry
    Registry <|-- EntryPointRegistry
```

- 基类 `Registry[RegistryItemType]` 在 [registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) 中定义，使用 `Generic[RegistryItemType]` 进行类型参数化。
- `OrderedRegistry` 通过重写 `on_item_registered` 与 `on_item_unregistered` 两个钩子，记录 `id(item)` 在 `_key_order` 中的插入顺序，从而实现有序迭代。
- `EntryPointRegistry` 在 `populate()` 中调用标准库 `importlib.metadata.entry_points` 加载第三方插件，并允许子类通过 `_value_from_entry_point` 钩子介入转换过程。

## 内部数据结构与状态机

`Registry` 实例在 `__init__` 时构造三块核心内部状态（参见 [registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)）：

| 内部成员 | 用途 |
| --- | --- |
| `_items: set[RegistryItemType]` | 用于去重与快速判断成员关系 |
| `_registry: dict[str, dict[object, RegistryItemType]]` | 按 `lookup_attrs` 中声明的每个属性名，建立"属性值 → 条目"的多层映射 |
| `_lock: RLock` | 可重入锁，包裹 `populate()`，保证首次填充只执行一次 |

注册中心通过 `RegistryState` 枚举暴露其生命周期状态机，定义于同一文件中：

```mermaid
stateDiagram-v2
    [*] --> PENDING: __init__
    PENDING --> POPULATING: populate() 进入锁
    POPULATING --> READY: get_defaults() 处理完成
    READY --> [*]
```

`state` 字段被外部消费者用于判断注册中心是否已完成首次默认填充（[registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)）。

## 泛型与类型系统

库通过 [registries/items.py](https://github.com/beanbaginc/python-registries/blob/main/registries/items.py) 暴露 `RegistryItemType = TypeVar('RegistryItemType')`，作为整个泛型体系的基础类型变量。该 TypeVar 在 `Registry` 子类化时被显式绑定（例如 `Registry[Type[BaseItem]]`），从而让 IDE 与静态分析工具能够识别 `register()`、`get()` 等方法的返回类型。

泛型也贯穿错误体系：`BaseRegistrationError`、`BaseRegistryItemLookupError` 等类（[registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)）均以 `RegistryItemType` 参数化，使得冲突、未找到、未匹配属性等异常能够携带具体条目对象，便于上层捕获并定位问题。

## 错误体系与可扩展钩子

错误类按职责分层——`BaseRegistryError` 为根，`BaseRegistrationError` / `BaseRegistryItemLookupError` / `BaseUnregistrationError` 三大分支分别处理注册、查找、注销阶段的异常（[registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)）。每个具体错误都提供 `message_template`，可被注册中心通过类属性（如 `registration_conflict_error_cls`）整体替换，从而支持自定义错误消息。

在钩子层面，`Registry` 提供了 `on_register`/`on_registered`、`on_unregister`/`on_unregistered`、`on_populated`、`on_reset` 等扩展点，子类（如 `OrderedRegistry`）通过重写这些方法实现自身语义而又不必触碰主流程。这种"模板方法 + 钩子"的设计，是整个库保持内核紧凑、外延灵活的关键。

## 设计要点小结

- **线程安全**：通过 `RLock` 保护 `populate()`，确保并发场景下默认填充只发生一次。
- **多属性查找**：通过 `_registry` 的二维结构同时支持 `lookup_attrs` 中的多个属性。
- **类型安全**：通过 `TypeVar` 与 `Generic` 把条目类型显式传递给下游消费方。
- **可扩展性**：通过错误类替换与钩子重写两条路径，覆盖绝大多数定制场景。

## See Also

- 项目首页与使用示例：[README.md](https://github.com/beanbaginc/python-registries/blob/main/README.md)
- 注册中心 API 与内置子类：[registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)
- 异常体系：[registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)
- 版本信息：[registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py)

---

<a id='page-3'></a>

## API Reference & Usage Patterns

### 相关页面

相关主题：[Architecture & Internal Design](#page-2), [Error Handling, Extensibility & Operations](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)
- [registries/__init__.py](https://github.com/beanbaginc/python-registries/blob/main/registries/__init__.py)
- [registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)
- [registries/items.py](https://github.com/beanbaginc/python-registries/blob/main/registries/items.py)
- [registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py)
- [README.md](https://github.com/beanbaginc/python-registries/blob/main/README.md)
</details>

# API 参考与使用模式

`python-registries` 是一个用于管理"注册表模式（Registry Pattern）"的 Python 库，源自 [Review Board](https://www.reviewboard.org) 项目并由 [Beanbag](https://www.beanbaginc.com) 开源。该库通过中心化的存储结构，让应用能够动态注册、注销以及按属性查询多个实现类（item），从而降低模块之间的耦合度并提升可扩展性。本页基于 `registries/` 包下的源码梳理其公开 API、典型使用模式以及错误处理约定。

## 1. 核心类与导出

包入口 `registries/__init__.py` 通过 `from registries.registry import ...` 暴露三个核心注册表类型，分别面向通用、有序以及 Python Entry Points 场景。 资料来源：[registries/__init__.py:23-26]()

| 类名 | 作用 | 适用场景 |
| --- | --- | --- |
| `Registry` | 通用注册表，存储唯一对象集合 | 抽象接口的多种后端实现 |
| `OrderedRegistry` | 在 `Registry` 基础上保留注册顺序 | 插件加载顺序、命令链 |
| `EntryPointRegistry` | 包装 Python Entry Points 的注册表 | 第三方扩展自动发现 |

类型参数 `RegistryItemType` 定义于 `registries/items.py`，是一个泛型 `TypeVar`，用于在子类化 `Registry` 时约束存储项的类型，例如 `Registry[Type[BaseItem]]`。 资料来源：[registries/items.py:1-17]()

版本号通过 `registries/_version.py` 中的 `VERSION` 元组提供，遵循 `(Major, Minor, Micro, tag, release_num, released)` 的格式，可通过 `get_version_string()` 或 `get_package_version()` 获取展示版本与打包版本。 资料来源：[registries/_version.py:1-25]()

## 2. Registry 的生命周期与状态机

`Registry` 实例在初始化时进入 `RegistryState.PENDING` 状态，并在首次调用 `populate()` 或 `get()` 等需要查询项的方法时，触发默认项加载流程 `POPULATING`，最终进入 `READY`。 资料来源：[registries/registry.py:48-58]()、资料来源：[registries/registry.py:78-83]()

```mermaid
stateDiagram-v2
    [*] --> PENDING: __init__()
    PENDING --> POPULATING: populate() / get()
    POPULATING --> READY: defaults 加载完成
    READY --> READY: register() / unregister()
    READY --> [*]: 进程结束
```

`populate()` 使用 `RLock` 保护，确保默认值只会被加载一次，后续注册与查询操作也运行在同一把锁下，从而保证多线程场景下的数据一致性。 资料来源：[registries/registry.py:57-65]()

子类可通过重写 `get_defaults()` 提供默认实现集合，例如 `README.md` 中展示的 `MyRegistry.get_defaults()` 返回 `[FooItem, BarItem]`。 资料来源：[README.md:55-78]()

## 3. 主要 API 方法

`Registry` 类的公开方法覆盖注册、查询、迭代与重置四大类：

- **注册**：`register(item)` 与 `unregister(item)` 用于动态增删项，调用前后会触发 `on_item_registered` / `on_item_unregistered` 钩子。 资料来源：[README.md:84-92]()、资料来源：[registries/registry.py:103-115]()
- **查询**：`get(*args, **kwargs)` 通过属性值精确定位单个项；`get_or_none(...)` 在未命中时返回 `None` 而不是抛出异常。两者都支持单位置参数（仅在 `lookup_attrs` 只有一个时可用）或 `attr_name=attr_value` 形式的 kwargs 查询。 资料来源：[registries/registry.py:117-156]()`、`[registries/registry.py:158-198]()`
- **迭代**：`__iter__` 默认以 `set` 形式返回已注册项；`OrderedRegistry` 通过额外的 `_by_id` 与 `_key_order` 列表维护注册顺序。 资料来源：[registries/registry.py:200-220]()`、`[registries/registry.py:228-260]()`
- **重置**：`populate()` 检查 `state == PENDING` 时重新加载 `get_defaults()`；如需重置后可使用 `reset()` 让状态回到 `PENDING`，以便重新填充。 资料来源：[registries/registry.py:80-98]()

类属性 `lookup_attrs: ClassVar[Sequence[str]]` 用于声明项的查询键，例如 `lookup_attrs = ('my_item_id',)`，与具体类属性同名以便自动建立反向索引。 资料来源：[README.md:60-78]()`、`[registries/registry.py:35-48]()`

## 4. 错误模型

`registries/errors.py` 定义了一套围绕注册与查询的异常类层次结构，所有异常都继承自 `BaseRegistryError`，其 `message_template` 使用基于 `%` 的格式化字符串。 资料来源：[registries/errors.py:35-50]()

| 异常 | 触发条件 |
| --- | --- |
| `InvalidItemRegistrationError` | 注册项缺少 `lookup_attrs` 中要求的属性 |
| `AlreadyRegisteredError` | 同一 `attr_value` 已被占用 |
| `RegistrationConflictError` | 注册过程中检测到冲突项 |
| `ItemNotFoundLookupError` | 查询时 `attr_value` 未命中 |
| `ItemNotFoundUnregistrationError` | 注销时未找到对应项 |
| `UnsupportedRegistryAttributeError` | 查询/注销时使用的属性名不在 `lookup_attrs` 中 |
| `AttrNotFoundUnregistrationError` | 注销时属性无法解析 |

每个异常都暴露了相关上下文（例如 `item`、`attr_name`、`attr_value`、`other_item`），方便上层做国际化或日志处理；子类可以自定义 `message_template` 来替换默认消息。 资料来源：[registries/errors.py:55-95]()`、`[registries/errors.py:96-150]()`

## 5. 常见使用模式

1. **默认值 + 动态扩展**：在子类中实现 `get_defaults()` 提供内置实现，运行期通过 `register()` 添加第三方实现。 资料来源：[README.md:55-92]()
2. **多属性联合查询**：将 `lookup_attrs` 设为多个属性名（如 `('id', 'name')`），注册时若任一属性冲突都会抛出 `RegistrationConflictError`，查询时按 kwargs 中的键路由到对应索引。 资料来源：[registries/registry.py:35-48]()`、`[registries/errors.py:55-95]()`
3. **钩子扩展**：重写 `on_item_registered`、`on_item_unregistered`、`on_populated` 与 `on_reset`，在不改写主流程的前提下插入缓存刷新、度量上报等逻辑。 资料来源：[registries/registry.py:103-115]()`、`[registries/registry.py:80-98]()`
4. **Entry Points 自动发现**：`EntryPointRegistry` 通过 `importlib.metadata.entry_points()` 加载指定 group 的入口；子类可重写 `_value_from_entry_point()` 把加载结果转换为目标类型。 资料来源：[registries/registry.py:200-228]()
5. **有序遍历**：在需要按注册顺序渲染（如命令链、中间件）的场景下使用 `OrderedRegistry`，其 `_key_order` 列表在 `on_item_registered` 时追加、在 `on_item_unregistered` 时按值移除，确保迭代顺序与注册顺序一致。 资料来源：[registries/registry.py:228-260]()

## See Also

- [Registries README](https://github.com/beanbaginc/python-registries/blob/main/README.md)
- [Registries on PyPI](https://pypi.org/project/registries/)
- [Review Board](https://www.reviewboard.org) —— 派生该库的项目
- [Djblets](https://github.com/djblets/djblets/) —— 同样使用注册表模式管理扩展

---

<a id='page-4'></a>

## Error Handling, Extensibility & Operations

### 相关页面

相关主题：[API Reference & Usage Patterns](#page-3), [Architecture & Internal Design](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py)
- [registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py)
- [registries/items.py](https://github.com/beanbaginc/python-registries/blob/main/registries/items.py)
- [registries/__init__.py](https://github.com/beanbaginc/python-registries/blob/main/registries/__init__.py)
- [registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py)
- [README.md](https://github.com/beanbaginc/python-registries/blob/main/README.md)
</details>

# Error Handling, Extensibility & Operations

## 概述

`python-registries` 库在注册、查询与注销项的过程中，提供了层次化的异常体系、可被子类覆盖的钩子接口、显式的运行时状态机以及线程安全的底层锁机制。这套设计使得开发者既能精细地控制错误信息，又能在不修改核心逻辑的前提下将注册流程嵌入到现有架构（如 Review Board）中。资料来源：[README.md](https://github.com/beanbaginc/python-registries/blob/main/README.md) 指出 "all thread-safe, all in your control"，正是本篇主题的集中体现。

## 错误类层次结构

`registries/errors.py` 定义了一套统一的异常基类与具体子类，所有异常均以 `%` 风格的格式化字符串生成消息，便于本地化与子类化。

```mermaid
classDiagram
    class BaseRegistryError {
        +message_template: ClassVar
        +__init__(message, **kwargs)
    }
    class UnsupportedRegistryAttributeError {
        +attr_name: str
    }
    class BaseRegistryItemLookupError {
        +attr_name: str
    }
    class ItemNotFoundLookupError {
        +attr_value: object
    }
    class BaseRegistrationError~RegistryItemType~ {
        +item: RegistryItemType
    }
    class AlreadyRegisteredError
    class RegistrationConflictError {
        +attr_name: str
        +attr_value: object
    }
    class InvalidItemRegistrationError {
        +attr_name: str
    }
    class BaseUnregistrationError
    class AttrNotFoundUnregistrationError
    class ItemNotFoundUnregistrationError
    BaseRegistryError <|-- UnsupportedRegistryAttributeError
    BaseRegistryError <|-- BaseRegistryItemLookupError
    BaseRegistryItemLookupError <|-- ItemNotFoundLookupError
    BaseRegistryError <|-- BaseRegistrationError
    BaseRegistrationError <|-- AlreadyRegisteredError
    BaseRegistrationError <|-- RegistrationConflictError
    BaseRegistrationError <|-- InvalidItemRegistrationError
    BaseRegistryError <|-- BaseUnregistrationError
    BaseUnregistrationError <|-- AttrNotFoundUnregistrationError
    BaseUnregistrationError <|-- ItemNotFoundUnregistrationError
```

资料来源：[registries/errors.py](https://github.com/beanbaginc/python-registries/blob/main/registries/errors.py) 中的 `BaseRegistryError.__init__` 方法会优先使用传入的 `message` 模板，否则回退到类属性 `message_template`，并通过 `%` 格式化注入 `attr_name`、`attr_value`、`item` 等命名参数。

## 错误处理在注册流程中的体现

`Registry` 类通过类属性把每一种具体异常绑定为默认错误类，并允许子类覆盖它们以定制错误消息。下面的表格列出了主要异常属性及其触发时机：

| 异常属性 | 默认异常类 | 抛出场景 | 来源 |
|---|---|---|---|
| `already_registered_error_cls` | `AlreadyRegisteredError` | 同一对象已存在 `_items` 集合中 | [registry.py:register](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |
| `registration_conflict_error_cls` | `RegistrationConflictError` | 同一 `lookup_attrs` 值已被其他项占用 | [registry.py:register](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |
| `invalid_item_registration_error_cls` | `InvalidItemRegistrationError` | 项缺失必要的查询属性 | [registry.py:register](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |
| `item_not_found_lookup_error_cls` | `ItemNotFoundLookupError` | `get()` 未匹配到任何项 | [registry.py:get](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |
| `unsupported_registry_attr_error_cls` | `UnsupportedRegistryAttributeError` | 查询键不在 `lookup_attrs` 内 | [registry.py:get](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |
| `item_not_found_unregistration_error_cls` | `ItemNotFoundUnregistrationError` | 通过对象注销时未找到该对象 | [registry.py:unregister](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |
| `attr_not_found_unregistration_error_cls` | `AttrNotFoundUnregistrationError` | 通过属性注销时未找到匹配项 | [registry.py:unregister](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) |

子类只需将对应类属性替换为自定义异常类，即可输出特定格式的错误消息，例如：

```python
class StrictRegistry(Registry[Type[BaseItem]]):
    lookup_attrs = ('my_item_id',)

    registration_conflict_error_cls = StrictConflictError
    item_not_found_lookup_error_cls = StrictMissingError
```

## 可扩展性钩子

`Registry` 在关键生命周期节点提供了一系列可重写的钩子方法，配合状态机可以无缝嵌入到第三方架构中。资料来源：[registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) 暴露了以下钩子：

- `on_populating()` — 在 `populate()` 开始时调用，可用于锁定外部资源或记录日志。
- `on_populated()` — 在 `populate()` 完成后、状态切换为 `READY` 之前调用。
- `on_item_registering(item)` / `on_item_registered(item)` — 包裹在 `_lock` 内，仅当注册成功后才触发 `on_item_registered`。
- `on_item_unregistering(item)` / `on_item_unregistered(item)` — 同上，针对注销流程。
- `on_reset()` — 在 `reset()` 完成清理后被调用，便于外部缓存或插件系统同步状态。

这些钩子都是普通方法，没有任何装饰器约束，子类直接重写即可生效。`README.md` 也强调了 "Hooks for customization the registration and lookup process, to tie into other pieces of your architecture."

## 运行时状态机

`RegistryState` 枚举用于追踪注册表在生命周期中的状态变更：

```mermaid
stateDiagram-v2
    [*] --> PENDING: __init__()
    PENDING --> POPULATING: populate()
    POPULATING --> POPULATING: 递归或重入
    POPULATING --> READY: get_defaults() 完成
    READY --> READY: register()/unregister()
    READY --> PENDING: reset()
    READY --> [*]
```

资料来源：[registries/registry.py](https://github.com/beanbaginc/python-registries/blob/main/registries/registry.py) 中 `RegistryState` 定义了三个状态：`PENDING`、`POPULATING`、`READY`。`populate()` 在锁内先检查状态，再切换到 `POPULATING`，调用 `get_defaults()` 加载默认项，最终进入 `READY`。如果调用 `reset()`，状态会回到 `PENDING`，下一次访问会自动重新触发 `populate()`。

## 线程安全与运维考量

- **锁机制**：`Registry.__init__` 创建 `RLock` 实例 `_lock`，所有读写操作均在该锁内完成。`register()`、`unregister()`、`populate()` 和 `reset()` 都遵循 "先 `populate()`，再加锁" 的模式，避免锁内递归。
- **类型提示**：`Registry[RegistryItemType]` 使用泛型参数 [registries/items.py](https://github.com/beanbaginc/python-registries/blob/main/registries/items.py) 中的 `RegistryItemType` 类型变量，可以在静态检查工具下获得完整推断。
- **版本兼容**：[registries/_version.py](https://github.com/beanbaginc/python-registries/blob/main/registries/_version.py) 当前版本为 `(1, 0, 1, 'alpha', 0, False)`，`is_release()` 返回 `False`，意味着下游生产环境应锁定为最终发布版。
- **包入口**：[registries/__init__.py](https://github.com/beanbaginc/python-registries/blob/main/registries/__init__.py) 统一对外导出 `Registry`、`OrderedRegistry`、`EntryPointRegistry` 及版本辅助函数，方便运维脚本快速获取版本号。

## 常见错误模式

1. **属性未定义**：注册时如果对象缺少 `lookup_attrs` 中的字段，会抛出 `InvalidItemRegistrationError`。建议在基类中显式声明占位符或 `None`，而不是依赖动态属性。
2. **重复注册**：`AlreadyRegisteredError` 与 `RegistrationConflictError` 的区别在于前者是同一个对象再次注册，后者是不同的对象恰好共享了同一个查询键值。
3. **状态误用**：在 `PENDING` 状态下手动调用 `register()` 实际是合法的，因为 `register()` 内部会先调用 `populate()`，但如果在自定义钩子中假设状态已经是 `READY`，就会出错。
4. **钩子阻塞**：钩子方法运行在锁内，如果在其中执行 I/O 或调用其他注册表的写操作，可能造成死锁。建议钩子只做轻量级通知（例如发布事件），将重负载逻辑派发到异步队列。

## 总结

`python-registries` 通过结构化的异常、可覆盖的钩子与显式的状态机，把错误处理、扩展性与运行时控制三件事紧密地整合在同一组 API 中。开发者既能直接使用默认行为，也能在不破坏线程安全的前提下注入业务规则，这是该库能被 Review Board 等大型项目长期依赖的关键因素。

## See Also

- [README.md](https://github.com/beanbaginc/python-registries/blob/main/README.md)
- [Registries 1.0 Release Notes](https://github.com/beanbaginc/python-registries/releases/tag/release-1.0)

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：beanbaginc/python-registries

摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：身份坑 - 仓库名和安装名不一致。

## 1. 身份坑 · 仓库名和安装名不一致

- 严重度：medium
- 证据强度：runtime_trace
- 发现：仓库名 `python-registries` 与安装入口 `registries` 不完全一致。
- 对用户的影响：用户照着仓库名搜索包或照着包名找仓库时容易走错入口。
- 复现命令：`pip install registries`
- 证据：identity.distribution | github_repo:805924052 | https://github.com/beanbaginc/python-registries | repo=python-registries; install=registries

## 2. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | github_repo:805924052 | https://github.com/beanbaginc/python-registries | README/documentation is current enough for a first validation pass.

## 3. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | github_repo:805924052 | https://github.com/beanbaginc/python-registries | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | github_repo:805924052 | https://github.com/beanbaginc/python-registries | no_demo; severity=medium

## 5. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | github_repo:805924052 | https://github.com/beanbaginc/python-registries | no_demo; severity=medium

## 6. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | github_repo:805924052 | https://github.com/beanbaginc/python-registries | issue_or_pr_quality=unknown

## 7. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | github_repo:805924052 | https://github.com/beanbaginc/python-registries | release_recency=unknown

<!-- canonical_name: beanbaginc/python-registries; human_manual_source: deepwiki_human_wiki -->
