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

生成时间：2026-06-14 16:12:05 UTC

## 目录

- [Overview and Installation](#page-1)
- [Function and Runtime Typing Utilities](#page-2)
- [JSON Structure Typing](#page-3)
- [Django Typing Extensions](#page-4)

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

## Overview and Installation

### 相关页面

相关主题：[Function and Runtime Typing Utilities](#page-2), [JSON Structure Typing](#page-3), [Django Typing Extensions](#page-4)

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

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

- [README.md](https://github.com/beanbaginc/python-typelets/blob/main/README.md)
- [typelets/__init__.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/__init__.py)
- [typelets/_version.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/_version.py)
- [typelets/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)
- [typelets/funcs.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/funcs.py)
- [typelets/symbols.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py)
- [typelets/runtime.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/runtime.py)
- [typelets/django/models.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/models.py)
</details>

# Overview and Installation

## 项目概述

Typelets 是由 Beanbag 公司发布的 Python 类型注解工具模块，主要用于增强 Python 标准库以及第三方库所提供的类型。该项目最初是为开发代码评审工具 Review Board 而构建的，现以 MIT 许可证开放给其他项目使用 资料来源：[README.md:1-15]()。

从定位上看，Typelets 并不试图取代 Python 现有的类型系统，而是作为 `typing` 与 `typing_extensions` 的补充，提供一些项目中常见的、被反复需要的"专用类型别名"和"运行时工具"。其涵盖范围包括通用 Python 类型补充以及面向 Django 框架的类型补充两个层次 资料来源：[README.md:9-39]()。

模块通过 `typelets/__init__.py` 暴露版本相关符号，例如 `VERSION`、`__version__`、`__version_info__`、`get_package_version`、`get_version_string` 与 `is_release` 资料来源：[typelets/__init__.py:1-25]()。

## 模块结构

Typelets 包内的代码按照"通用 Python"与"Django 集成"两条主线组织，便于使用者按需引入。下表汇总了各子模块的核心职责：

| 子模块 | 主要职责 | 代表符号 / 类型 |
|--------|----------|-----------------|
| `typelets.funcs` | 函数与方法的类型增强 | `KwargsDict`、`MethodDirective`、`TParams`、`TReturn_co` |
| `typelets.json` | JSON 结构与可序列化数据 | `JSONValue`、`JSONDict`、`JSONDictImmutable`、`JSONList`、`BaseSerializableJSONValue` |
| `typelets.runtime` | 运行时类型检查工具 | `raise_invalid_type` |
| `typelets.symbols` | 标记"未设置"的符号 | `UnsetSymbol`、`UNSET`、`Unsettable` |
| `typelets.django.auth` | 接收用户对象的类型 | （见官方文档） |
| `typelets.django.forms` | 表单与表单字段类型 | `FormData`、`FormFiles` |
| `typelets.django.json` | Django JSON 序列化类型 | `SerializableDjangoJSONValue` |
| `typelets.django.models` | Django 模型主键类型 | `ModelAnyPK`、`ModelIntPK` |
| `typelets.django.strings` | 本地化字符串类型 | `StrOrPromise`、`StrPromise` |
| `typelets.django.urls` | URL 注册类型 | `AnyURL` |

例如，`typelets.json` 中定义了可递归展开的 JSON 值联合类型 `JSONValue`，以及对应的可变字典 `JSONDict` 与不可变映射 `JSONDictImmutable` 资料来源：[typelets/json.py:18-74]()。`typelets.symbols` 则使用 `Enum` 配合 `Literal` 与 `Final` 来表达"未设置"语义，从而区分函数默认值中的"未提供"与"`None`/`False`" 资料来源：[typelets/symbols.py:14-53]()。在 Django 方向，`typelets.django.models` 提供了 `ModelAnyPK` 与 `ModelIntPK` 两个主键类型别名，以替代 Django 默认不够明确的 `Any` 资料来源：[typelets/django.models.py:14-50]()。

## 安装与版本

Typelets 已发布到 PyPI，可通过 `pip` 直接安装。安装命令如下：

```console
$ pip install typelets
```

安装完成后即可在 Python 项目中 `import typelets` 引入相关类型别名。版本方面，仓库当前维护的版本为 `(1, 2, 0, 'alpha', 0, False)`，可通过 `typelets._version` 提供的辅助函数读取 资料来源：[typelets/_version.py:9-72]()。

`get_version_string()` 会生成面向显示的版本字符串（例如 `1.2 alpha 0 (dev)`），`get_package_version()` 则生成符合 PEP 440 的包版本字符串（例如 `1.2a0`），二者均会根据 `is_release()` 的返回值追加 `(dev)` 后缀，以区分开发版与正式发布版 资料来源：[typelets/_version.py:19-72]()。项目遵循语义化版本（Semantic Versioning），在升级时不会引入不兼容变更 资料来源：[README.md:55-58]()。

## 贡献与许可证

Typelets 采用 MIT 许可证发布，用户可以自由地在自有项目中复用其类型定义 资料来源：[README.md:64-66]()。

代码贡献通过 Beanbag 运营的 Review Board 代码评审服务器（`https://reviews.reviewboard.org/`）进行。典型的提交流程是先安装 RBTools：

```console
$ pip install rbtools
```

随后在本地克隆中创建分支并做出修改，使用 `rbt post` 提交评审；后续更新则使用 `rbt post -u` 资料来源：[README.md:68-87]()。除 Typelets 外，Beanbag 还在 GitHub 上维护 Review Board、Djblets、Housekeeping、kgb 与 Registries 等多个相关项目 资料来源：[README.md:91-115]()。

## 另请参阅

- 运行时工具：[typelets.runtime](https://github.com/beanbaginc/python-typelets/blob/main/typelets/runtime.py) — `raise_invalid_type` 用作带类型的运行时守卫。
- JSON 类型体系：[typelets.json](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py) — JSON 容器与可序列化基类的定义。
- 符号与"未设置"语义：[typelets.symbols](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py) — `UNSET` 与 `Unsettable` 类型别名。
- 官方文档：[Typelets Documentation](https://typelets.readthedocs.io/) — 各模块的完整 API 参考。

---

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

## Function and Runtime Typing Utilities

### 相关页面

相关主题：[Overview and Installation](#page-1), [JSON Structure Typing](#page-3)

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

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

- [typelets/funcs.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/funcs.py)
- [typelets/runtime.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/runtime.py)
- [typelets/symbols.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py)
- [typelets/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)
- [typelets/django/strings.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/strings.py)
- [typelets/__init__.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/__init__.py)
- [typelets/_version.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/_version.py)
</details>

# 函数与运行时类型工具（Function and Runtime Typing Utilities）

## 一、概述与设计目标

`python-typelets` 是由 Beanbag 公司为支撑 [Review Board](https://www.reviewboard.org/) 项目而开发的 Python 类型扩展库。其核心目的是在不破坏运行时性能的前提下，弥补标准库 `typing` 与第三方类型工具在函数签名复用、运行时类型守卫以及"未设置"语义上的不足。

本主题聚焦于该项目的三大功能模块：

| 模块 | 主要职责 |
| --- | --- |
| [`typelets.funcs`](typelets/funcs.py) | 复用函数/方法签名，构造可携带 `ParamSpec` 的装饰器 |
| [`typelets.runtime`](typelets/runtime.py) | 提供比 `typing.assert_never` 更灵活的运行时异常抛出 |
| [`typelets.symbols`](typelets/symbols.py) | 通过 `UnsetSymbol` 区分"未传入"与"显式为 None/False" |

这三者被 [`typelets/__init__.py`](typelets/__init__.py) 与 [`typelets/_version.py`](typelets/_version.py) 管理，当前公开版本字符串由 `VERSION = (1, 2, 0, 'alpha', 0, False)` 推导而来，遵循 PEP 440 规范。资料来源：[typelets/__init__.py:1-22]()、[typelets/_version.py:8-25]()。

---

## 二、函数签名复用：`typelets.funcs`

### 2.1 基础类型别名与协议

`typelets.funcs` 模块首先定义了一组可被其他模块复用的 `TypeVar` / `ParamSpec`：

- `TParams: ParamSpec` —— 用于引用某个可调用对象的参数列表，1.1 版本引入；资料来源：[typelets/funcs.py:30-32]()。
- `TReturn_co: TypeVar(covariant=True)` —— 协变的返回值类型变量；资料来源：[typelets/funcs.py:37-39]()。
- `TOwner: TypeVar(bound=object)` —— 方法所属的宿主类；资料来源：[typelets/funcs.py:43-44]()。
- `KwargsDict: TypeAlias = Dict[str, Any]` —— 用于标注通用 `**kwargs`，1.0 版本起可用；资料来源：[typelets/funcs.py:49-50]()。

为了让返回"未绑定方法"的 API 仍然能被类型检查器视为方法签名，模块定义了 `MethodDirective[TOwner, TParams, TReturn_co]` 协议类，并通过 `__self__: TOwner` 将宿主类与签名绑定起来；资料来源：[typelets/funcs.py:55-72]()。

### 2.2 通过基类继承另一函数的签名

`BaseParamsFromFunc[TParams]` 与 `BaseParamsFromMethod[TParams, TOwner]` 是用于**重新指定函数签名**的基类。它们的共同模式是：

1. 子类继承基类并提供 `TParams`。
2. 子类实现 `__call__`，**必须**返回 `Any`。
3. 子类 `__call__` 的形参表（包含 `*args: TParams.args` 与 `**kwargs: TParams.kwargs`）会被拷贝到被装饰函数上。

模块同时提供两个便捷子类：`OnlyParamsFromFunc` 与 `OnlyParamsFromMethod`，用于"装饰函数本身就只是参数转发"的常见场景。资料来源：[typelets/funcs.py:84-150]()。

### 2.3 工作流图

下图展示了装饰器 `type_func_params_as` 在装饰阶段如何替换 `__signature__` 与 `__annotations__`，而运行阶段零开销：

```mermaid
flowchart LR
    A[用户函数<br/>my_function] --> B[定义签名子类<br/>MyParamsFromFunc]
    B --> C{应用装饰器<br/>type_func_params_as}
    C --> D[读取 subclass.__call__<br/>的签名]
    D --> E[patch 原函数的<br/>__annotations__<br/>与 __signature__]
    E --> F[运行时调用<br/>零额外开销]
    F --> G[(类型检查器按<br/>新签名静态校验)]
```

实现细节可参见源码注释：装饰过程仅在装饰时发生，运行时不引入任何额外调用成本。资料来源：[typelets/funcs.py:96-150]()。

### 2.4 已知陷阱

- 由于 PyLance 通过首个可调用对象推断 docstring，使用本装饰器**可能**在 VS Code 中丢失文档；参考资料 [microsoft/pylance-release#5840](https://github.com/microsoft/pylance-release/issues/5840)。资料来源：[typelets/funcs.py:107-112]()。
- 子类 `__call__` 必须包含 `self`，即便被装饰函数并不需要 `self`；且 `*` / `/` / `**kwargs` 必须显式保留。资料来源：[typelets/funcs.py:130-148]()。

---

## 三、运行时类型守卫：`typelets.runtime`

`typelets.runtime` 仅导出一个工具函数 `raise_invalid_type`，其签名为：

```python
def raise_invalid_type(
    value: Never,
    message: str,
    exception_type: type[Exception] = ValueError,
) -> Never
```

它与标准库的 `typing.assert_never` 类似，但具备两个显著的扩展：

1. **可定制异常类型**：默认抛出 `ValueError`，但允许传入任何 `Exception` 子类，避免在公共 API 中抛出语义不友好的 `AssertionError`。资料来源：[typelets/runtime.py:12-44]()。
2. **支持自定义消息**：通过 `message` 参数传入人类可读的错误描述，便于调用方进行国际化或调试。

由于参数类型为 `Never`，类型检查器会把所有"未到达此函数"的分支视为不可达，从而安全地用作类型守卫。资料来源：[typelets/runtime.py:17-29]()。

---

## 四、标记"未设置"：`typelets.symbols`

`typelets.symbols` 模块解决了一个典型的 API 痛点：如何区分"调用方未传参"与"调用方显式传入 `None` 或 `False`"。它定义了：

- `UnsetSymbol(Enum)` —— 枚举类，仅有 `UNSET = '<UNSET>'` 一个成员；资料来源：[typelets/symbols.py:22-29]()。
- `UNSET: Final[Literal[UnsetSymbol.UNSET]]` —— 模块级单例，方便函数默认值直接使用；资料来源：[typelets/symbols.py:34-35]()。
- `Unsettable: TypeAlias = Union[Literal[UnsetSymbol.UNSET], _T]` —— 通用泛型别名，使任意类型可被"标为可未设置"；资料来源：[typelets/symbols.py:46-58]()。

典型用法示例（来源于 docstring）：

```python
def __init__(self, value: Unsettable[str]) -> None:
    if value is UNSET:
        ...
    else:
        # 此处 value 被类型检查器收窄为 str
        ...
```

这种模式与 [`typelets/django/strings.py`](typelets/django/strings.py) 中的 `StrOrPromise`、`typelets/django/forms.py` 中的 `FormData` 等类型配合，可让函数签名既支持可空又支持未传。资料来源：[typelets/symbols.py:36-58]()、[typelets/django/strings.py:30-40]()。

---

## 五、典型应用场景

1. **包裹第三方 API**：当一个函数只是把参数透传给另一个函数时，使用 `BaseParamsFromFunc` 配合 `type_func_params_as`，可避免重复书写形参列表，同时保留 IDE 智能提示。资料来源：[typelets/funcs.py:96-112]()。
2. **公共 API 的运行时校验**：在分派前使用 `raise_invalid_type` 抛出业务异常，类型检查器视该分支为穷尽。资料来源：[typelets/runtime.py:17-44]()。
3. **JSON 与 Django 序列化扩展**：[`typelets/json.py`](typelets/json.py) 提供的 `BaseSerializableJSONValue[_T]` 等泛型与 [`typelets/django/json.py`](typelets/django/json.py) 提供的 `SerializableDjangoJSONValue` 均通过 `_T` 注入扩展类型，使 JSON 模型可以携带 `datetime`、`Decimal`、`UUID`、`StrPromise` 等原生 JSON 不直接支持的对象。资料来源：[typelets/json.py:30-110]()。

---

## 六、版本与导出

`typelets` 包对外暴露的元数据全部来自 `typelets/_version.py`：

- `VERSION` —— 六元组，用于内部版本比较；
- `get_version_string()` —— 形如 `1.2 alpha 0 (dev)` 的展示版本；
- `get_package_version()` —— PEP 440 兼容字符串，形如 `1.2a0`；
- `is_release()` —— 是否为正式发布版本。

这些符号通过 [`typelets/__init__.py`](typelets/__init__.py) 的 `__all__` 统一导出，并使用 `__autodoc_excludes__` 防止 Sphinx 重复生成文档。资料来源：[typelets/__init__.py:7-22]()、[typelets/_version.py:8-60]()。

---

## 七、See Also

- [Typelets 项目主页与概览](README.md)
- [JSON 与可序列化类型](typelets/json.py)
- [Django Forms 类型](typelets/django/forms.py)
- [Django Models 主键类型](typelets/django/models.py)
- [Django 国际化字符串类型](typelets/django/strings.py)
- [Django URL 注册类型](typelets/django/urls.py)
- [上游文档：typelets.readthedocs.io](https://typelets.readthedocs.io/)

---

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

## JSON Structure Typing

### 相关页面

相关主题：[Overview and Installation](#page-1), [Function and Runtime Typing Utilities](#page-2)

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

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

- [typelets/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)
- [typelets/django/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/json.py)
- [typelets/django/strings.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/strings.py)
- [typelets/funcs.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/funcs.py)
- [typelets/symbols.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py)
- [typelets/_version.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/_version.py)
- [README.md](https://github.com/beanbaginc/python-typelets/blob/main/README.md)
</details>

# JSON 结构类型定义

## 概述与设计目标

`typelets` 项目是由 Beanbag 维护的 Python 类型增强工具库，其设计目的是为 Python 与第三方库中已经存在的基础类型提供更精确、更贴合实际业务场景的补充类型（[README.md](https://github.com/beanbaginc/python-typelets/blob/main/README.md)）。其中 **JSON 结构类型定义** 是核心模块之一，集中在 [typelets/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py) 中实现，并配套提供面向 Django 项目的扩展类型，位于 [typelets/django/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/json.py)。

该模块主要解决两个痛点：

1. **原生 JSON 数据结构缺乏精确类型描述**。`typing` 提供的 `Dict[str, Any]` 无法体现嵌套的可序列化值，导致静态检查与重构受阻。
2. **应用自定义的可序列化类型（如 `datetime`、`UUID`）无法被标准库精确表达**。`Base*` 系列泛型类型把这一层差异抽象出来，供消费者按需扩展。

## 基础 JSON 类型体系

`typelets/json.py` 提供了 5 个基础类型别名，全部以 `TypeAlias` 形式导出，便于类型检查器推断 [资料来源：[typelets/json.py:1-13]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)：

| 类型别名 | 底层表示 | 是否可变 | 主要用途 |
|---------|---------|---------|---------|
| `JSONValue` | `Union[JSONDict, JSONDictImmutable, JSONList, JSONListImmutable, None, bool, float, int, str]` | — | 表达任意合法的 JSON 值 |
| `JSONDict` | `Dict[str, JSONValue]` | 可变 | 可读写的 JSON 字典 |
| `JSONDictImmutable` | `Mapping[str, JSONValue]` | 不可变 | 用于类型收窄，标记不可写 |
| `JSONList` | `List[JSONValue]` | 可变 | 可读写的 JSON 列表 |
| `JSONListImmutable` | `Sequence[JSONValue]` | 不可变 | 用于类型收窄，标记不可写 |

其中 `JSONValue` 借助前向引用（字符串字面量）递归地把 `JSONDict` 与 `JSONList` 包裹进来，从而自然支持任意深度的嵌套结构 [资料来源：[typelets/json.py:18-30]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)。可变与不可变两种版本的并存，使得函数可以根据是否需要修改结果选择不同别名，例如返回值推荐使用 `JSONDictImmutable`，从而帮助类型收窄并避免调用方误改 [资料来源：[typelets/json.py:46-53]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)。

## 泛型可序列化扩展

为了支持项目自定义的可序列化对象（例如 `datetime` 或 `UUID`），`typelets/json.py` 引入了一个 `TypeVar _T` 与 5 个 `Base*` 泛型类型别名。这些 `Base*` 类型的职责是为消费者提供一个**“框架类型”**，再由消费者自定义具体的子类型 [资料来源：[typelets/json.py:64-119]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)。

```python
SerializableJSONValue: TypeAlias = \
    BaseSerializableJSONValue[Union[datetime, UUID]]
```

上述示例展示了一种典型用法：把 `datetime` 与 `UUID` 注入到泛型参数中，即可得到应用专用的可序列化值类型。整体的设计哲学是“**基底通用、调用方定制**”，这与项目一贯的 `Typelets` 风格一致：把 `from __future__ import annotations` 与 `typing_extensions.TypeAlias` 组合使用，从而兼容较旧的 Python 解释器 [资料来源：[typelets/json.py:1-12]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)。

下面是 `Base*` 类型的整体关系图。

```mermaid
graph TD
    V[BaseSerializableJSONValue[T]]
    D[BaseSerializableJSONDict[T]]
    DI[BaseSerializableJSONDictImmutable[T]]
    L[BaseSerializableJSONList[T]]
    LI[BaseSerializableJSONListImmutable[T]]
    JV[JSONValue]
    V --> JV
    V --> T[T: 消费者自定义类型]
    D --> V
    DI --> V
    L --> V
    LI --> V
```

## Django 专属可序列化类型

Django 项目常常需要把 `Decimal`、`UUID`、`datetime`、`date`、`time`、`timedelta` 等类型写入 JSON 响应。`typelets/django/json.py` 在 `Base*` 泛型之上把这些类型组合起来，并声明了 `_SerializableJSONValueTypes` 私有别名 [资料来源：[typelets/django/json.py:18-27]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/json.py)。其中 `StrPromise` 来自 [typelets/django/strings.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/strings.py)，用以表示 Django 的延迟翻译字符串（lazy translation）。

随后模块对外公开 5 个别名（`SerializableDjangoJSONValue`、`SerializableDjangoJSONDict`、`SerializableDjangoJSONDictImmutable`、`SerializableDjangoJSONList`、`SerializableDjangoJSONListImmutable`），其底层分别绑定到 `BaseSerializableJSONValue[_SerializableJSONValueTypes]` 等泛型 [资料来源：[typelets/django/json.py:35-89]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/json.py)。这一组类型与 `DjbletsJSONEncoder` 实际支持的数据类型保持一致，使得类型声明与运行时序列化器能力同步。

## 集成与最佳实践

- **版本要求**：`typelets` 的当前版本为 `1.2.0a0`（[typelets/_version.py:8](https://github.com/beanbaginc/python-typelets/blob/main/typelets/_version.py)），遵循语义化版本控制 [资料来源：[README.md:55-58]()](https://github.com/beanbaginc/python-typelets/blob/main/README.md)。
- **搭配运行期检查**：`typelets.runtime` 模块提供运行期类型检查工具，可与 `JSONValue` 系列静态类型配合使用，构成“静态声明 + 动态校验”的双重防线。
- **搭配 `Unsettable` 模式**：使用 [typelets/symbols.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py) 中的 `Unsettable[T]` 别名，可以表达“未设置”或“显式提供 `None`”的差异；这在 API 序列化层尤为常见 [资料来源：[typelets/symbols.py:30-44]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py)。
- **搭配 `KwargsDict`**：[typelets/funcs.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/funcs.py) 提供的 `KwargsDict = Dict[str, Any]` 在构造可序列化载荷时尤为便利 [资料来源：[typelets/funcs.py:1-30]()](https://github.com/beanbaginc/python-typelets/blob/main/typelets/funcs.py)。

## 常见误区

1. **把不可变别名当作可变容器**：`JSONListImmutable` 实际是 `Sequence`，调用 `.append()` 会在运行期抛出 `AttributeError`，类型检查器也会发出警告。
2. **自行拼装 `Base*` 泛型而遗漏 `_T`**：`BaseSerializableJSONDict` 等类型必须显式提供类型参数，否则静态检查器会报错。
3. **Django 项目中混用纯 JSON 类型**：Django 的 `JSONField`、`DecimalField` 等会输出 `Decimal` 等类型，必须改用 `SerializableDjangoJSON*` 系列，否则静态类型与实际运行时数据不匹配。

## 参见

- [README.md](https://github.com/beanbaginc/python-typelets/blob/main/README.md) — 项目总览
- [typelets/django/strings.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/strings.py) — `StrPromise` 的定义
- [typelets/django/forms.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/forms.py) — Django 表单类型
- [typelets/django/models.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/models.py) — Django 模型主键类型
- [Typelets 官方文档](https://typelets.readthedocs.io/) — 完整 API 参考

---

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

## Django Typing Extensions

### 相关页面

相关主题：[Overview and Installation](#page-1), [JSON Structure Typing](#page-3)

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

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

- [typelets/django/auth.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/auth.py)
- [typelets/django/forms.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/forms.py)
- [typelets/django/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/json.py)
- [typelets/django/models.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/models.py)
- [typelets/django/strings.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/strings.py)
- [typelets/django/urls.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/django/urls.py)
- [typelets/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py)
- [README.md](https://github.com/beanbaginc/python-typelets/blob/main/README.md)
- [dev-requirements.txt](https://github.com/beanbaginc/python-typelets/blob/main/dev-requirements.txt)
</details>

# Django Typing Extensions

## 概述与定位

`typelets/django` 是 `python-typelets` 库中专门面向 Django 框架的类型别名子包。它并未引入运行期逻辑——除 `strings.py` 中用于回避 Sphinx 文档识别冲突的 `NewType` 占位声明外，其余文件仅通过 `typing_extensions.TypeAlias` 暴露静态类型提示。资料来源：[typelets/django/strings.py:1-50]()、[typelets/django/urls.py:1-25]()

子包存在的主要动机，是为常见 Django 对象（用户、表单、模型、URL、JSON、字符串）提供比 Django 内置注解或 `typing.Any` 语义更清晰、可被 `mypy`、`pyright` 及 `django-stubs` 准确推断的类型。所有 Django 模块统一在文件头部使用 `from __future__ import annotations`，并优先选择 `typing_extensions.TypeAlias`，从而兼容尚未实现 PEP 613 的旧解释器。资料来源：[typelets/django/auth.py:1-15]()、[typelets/django/forms.py:1-23]()

## 子包结构

子包严格按 Django 子领域切分，每个文件只暴露少量语义明确的别名。下表总结各模块的职责、主要导出符号与依赖关系：

| 模块 | 职责 | 关键导出 | 依赖 |
| --- | --- | --- | --- |
| `typelets/django/auth.py` | 接纳登录用户与匿名用户 | `AnyUser` | `django.contrib.auth.models` |
| `typelets/django/forms.py` | 表单字段与上传文件 | `FormData`、`FormFiles` | `django.core.files.uploadedfile`、`django.utils.datastructures` |
| `typelets/django/json.py` | 可序列化 JSON 的 Django 值 | `SerializableDjangoJSONValue` 等四个别名 | `typelets.json`、`typelets.django.strings` |
| `typelets/django/models.py` | 模型主键 | `ModelAnyPK`、`ModelIntPK` | 仅 `typing.Any` / `int` |
| `typelets/django/strings.py` | 国际化字符串 | `StrPromise`、`StrOrPromise` | `django.utils.functional` |
| `typelets/django/urls.py` | URL 注册 | `AnyURL` | `django.urls.resolvers` |

资料来源：[typelets/django/auth.py:14-16]()、[typelets/django/forms.py:16-22]()、[typelets/django/json.py:1-50]()、[typelets/django/models.py:20-45]()、[typelets/django/strings.py:1-50]()、[typelets/django/urls.py:17-25]()

## 核心类型详解

### 用户与认证

`AnyUser` 将 `AbstractBaseUser` 与 `AnonymousUser` 合并为单一 `Union`，常用于视图函数、API 端点、模板上下文等需要同时接纳登录与匿名用户的场景。资料来源：[typelets/django/auth.py:14-16]()

### 表单数据与上传文件

`FormData` 即 `Mapping[str, Any]`，表示请求体中的字段集合；`FormFiles` 则是 `MultiValueDict[str, UploadedFile]`，专门用于 `request.FILES`。两者直接复用 Django 自身的容器类型，因此不会与运行期结构产生偏差。资料来源：[typelets/django/forms.py:16-22]()

### 模型主键

Django 默认将 `pk` 注解为 `Any`，不利于阅读。`ModelAnyPK` 保留 `Any` 的灵活性，`ModelIntPK` 则收紧为 `int`，适合明确只使用自增整数主键的代码库。注意：它们仅作用于静态检查，运行期行为完全由 Django 决定。资料来源：[typelets/django/models.py:14-45]()

### 国际化字符串

`StrPromise` 与 `StrOrPromise` 专为 `gettext_lazy()` 这类惰性国际化字符串而设计。模块在 `TYPE_CHECKING` 分支下引用 Django 内部的 `_StrPromise` / `_StrOrPromise`；在运行期则回退为 `NewType('StrPromise', Promise)` 占位，从而避免 Sphinx 在生成文档时把这些别名误识别为模块属性。资料来源：[typelets/django/strings.py:14-50]()

### URL 注册

`AnyURL = Union[URLPattern, URLResolver]`，便于在 `urls.py` 中用同一变量类型同时表达具体的 `path()` 匹配与 `include()` 嵌套。资料来源：[typelets/django/urls.py:14-25]()

### 可序列化为 JSON 的 Django 值

`typelets/django/json.py` 在通用 `BaseSerializable*` 类型的基础上，将 `Decimal`、`StrPromise`、`UUID`、`date`、`datetime`、`time`、`timedelta` 组合为 `_SerializableJSONValueTypes` 联合，并据此参数化得到 `SerializableDjangoJSONValue`、`SerializableDjangoJSONDict`、`SerializableDjangoJSONList` 与 `SerializableDjangoJSONListImmutable`。这些别名与 `djblets.util.serializers.DjbletsJSONEncoder` 的能力保持一致，可在类型层面确保只把可序列化的值写入字段。资料来源：[typelets/django/json.py:14-50]()、[typelets/json.py:1-50]()

## 安装、依赖与运行期行为

`typelets` 通过 `pip install typelets` 安装（[README.md:1-50]()）。Django 相关类型要求目标项目已安装 Django；开发期间建议同时安装 `django-stubs` 以获得精确推断。从 `dev-requirements.txt` 可以看出，本项目在 Python 3.8（Django 3.2）与 Python ≥ 3.9（Django 4.2）两个解释器上均做测试。资料来源：[dev-requirements.txt:1-10]()

子包内部还与基础库紧密协作：`typelets/django/json.py` 通过 `from typelets.json import BaseSerializableJSONValue, ...` 复用通用 JSON 类型。这意味着一旦需要为自定义编码器扩展可序列化类型（例如新增某种数值类型），应优先在调用方定义新的 `TypeAlias`，而不是修改基础库，以保持子包解耦。资料来源：[typelets/json.py:1-50]()

## 常见误区

1. `ModelIntPK` 不会在运行期强制主键为整数——它只影响类型检查器。资料来源：[typelets/django/models.py:38-45]()
2. 运行期 `StrPromise` 实际是 `NewType` 占位，`isinstance(s, StrPromise)` 会失败，应改用 `isinstance(s, Promise)`。资料来源：[typelets/django/strings.py:18-23]()
3. `SerializableDjangoJSONValue` 系列只覆盖 `DjbletsJSONEncoder` 支持的类型集；若业务侧使用其他编码器，需要扩展联合类型。资料来源：[typelets/django/json.py:14-50]()

## See Also

- [README.md](https://github.com/beanbaginc/python-typelets/blob/main/README.md) — 库总览
- [typelets/json.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/json.py) — 通用 JSON 类型基类
- [typelets/runtime.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/runtime.py) — 运行时类型工具
- [typelets/symbols.py](https://github.com/beanbaginc/python-typelets/blob/main/typelets/symbols.py) — `UNSET` 等标记符号

---

<!-- evidence_pipeline_checked: true -->

---

## Doramagic 踩坑日志

项目：beanbaginc/python-typelets

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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