corespine
Reference

Extending

A how-to for consumers and third parties — add a seam implementation, wire a real backend behind an optional extra, or bind your own conformance invariants without touching corespine.

本文是操作指南:第三方包如何在不改 corespine 一行代码的前提下,给某条缝补一个实现、 接一个真实后端、绑自己的不变量。机制源码见 seam/registry.pyconformance/harness.py;宪章见 CLAUDE.md,增长判据见 roadmap,现状见 prd

corespine 只提供机制,扩展点全在缝上,三种方式互不耦合:

扩展方式解决什么关键 API章节
entry-point 扩展一条缝第三方装包即被 make 发现,无需改核心Registry.make / group corespine.<seam>
可选 extra + 延迟 import真实后端 SDK 只在选用时才 import,缺依赖给友好提示lazy_extra_import / [project.optional-dependencies]
给一条缝绑 conformance 不变量app 用自己的不变量逮住坏实现InvariantPack / ConformanceSuite

一、用 entry-point 扩展一条缝

每条缝是一个 Registry("<seam>") 实例;make(spec) 找不到内置名时,回落到 importlib.metadata 的 entry-point 自动发现,group 命名固定为 corespine.<seam>。 于是第三方只需在自己的 pyproject.toml 声明一个 entry point,装包即扩展,corespine 核心一行不改。

第三方包的 pyproject 片段

假设某条缝叫 vector_store,你的包 myadapter 想注册一个名为 pgvector 的实现:

# myadapter/pyproject.toml
[project.entry-points."corespine.vector_store"]
# 名字(左) -> "模块:工厂可调用对象"(右);工厂签名为 (**kwargs) -> 实现实例
pgvector = "myadapter.pg:make_pgvector"
# myadapter/pg.py
def make_pgvector(**kwargs):
    """工厂:返回一个实现该缝 Protocol 的实例(此处省略真实细节)。"""
    return PgVectorStore(**kwargs)

装包后的调用示例

from corespine import Registry

# 同一条缝名 "vector_store" 必须与 entry-point group 后缀一致。
registry: Registry = Registry("vector_store")

# 内置名找不到 → 自动扫 group "corespine.vector_store" 发现 myadapter 的 pgvector。
store = registry.make("pgvector", dsn="postgresql://...")

# 解析大小写 / 连字符 / 留白不敏感:"PG-Vector" / " pgvector " 都解析到同一项。
registry.names()  # 列出【内置 + entry-point 发现】的全部可用名(字典序、去重)

要点:

  • group 名必须corespine.<seam>,<seam>Registry("<seam>") 的入参完全一致;
  • 内置注册优先于 entry-point:同名时内置胜出(便于在测试里覆盖);
  • 发现是延迟的:只在 make / names 解析时才扫,不在 import 期付出代价;
  • 未知 spec 抛 ValueError,并列清当前全部可用名(绝不让人猜)。

二、可选 extra 命名约定

薄核宪章(ADR 0001 D5):核心 dependencies 永远为空,默认路径零重依赖。真实后端的 SDK(Redis / OpenAI / …)由各 app 在自己的缝里经可选 extra 声明,并用 lazy_extra_import 延迟 import —— 选用该 adapter 时才 import,没装就给出可直接照做的安装指引。

extra 命名约定

约定示例说明
一个真实后端 → 一个 extra,以后端命名[redis] / [openai]名字即"装哪个后端",直观可猜
extra 内只放该后端的 SDKredis = ["redis>=5"]不夹带无关依赖,装得最小
lazy_extra_importextra= 与之同名extra="redis"缺依赖时提示 pip install <pkg>[redis] 即可修
# 你的包 pyproject.toml:真实后端依赖声明为可选 extra(以后端命名)
[project.optional-dependencies]
redis = ["redis>=5"]
openai = ["openai>=1.0"]

lazy_extra_import 用法

lazy_extra_import(module, *, pkg, extra) 把裸 ImportError 翻译成 pip install <pkg>[<extra>] 的友好提示:

from corespine import lazy_extra_import


def make_redis_queue(**kwargs):
    # 只在真正构造该 adapter 时才 import;没装 redis 不影响核心离线默认路径。
    redis = lazy_extra_import("redis", pkg="myadapter", extra="redis")
    client = redis.Redis(**kwargs)
    return RedisQueue(client)

未装 redis 时调用 make_redis_queue(...) 会抛:

ImportError: 缺少可选依赖 'redis':请先 `pip install myadapter[redis]` 再重试。

—— 而不是让调用方对着 ModuleNotFoundError: No module named 'redis' 自己猜该装哪个 extra。

三、给一条缝绑 conformance 不变量

corespine 的 conformance 是机制,非保证:harness 只负责"跑 实现 × 不变量 的笛卡尔积 + 报告哪个格子坏了",具体不变量由各 app 自己绑(ADR 0001 D6)。app 把自己的 InvariantPack 喂进 ConformanceSuite 即可。

最小骨架(完整可跑范例见 examples/conformance_usage.py):

from corespine import ConformanceSuite, InvariantPack

# 1) 实现注册表:名字 -> 无参工厂(每格各新建实例,杜绝实现间状态串味)
impls = {"counter": Counter, "broken": BrokenCounter}

# 2) app 自己的不变量包(corespine 核心不含任何具体不变量)
pack = (
    InvariantPack("counter-contract")
    .add("first-add-returns-n", lambda c: assert_eq(c.add(3), 3))
    .add("accumulates", lambda c: assert_eq((c.add(2), c.add(5)), (2, 7)))
)

# 3) 绑成笛卡尔积,逐格跑
suite = ConformanceSuite(impls, pack)
for impl, invariant in suite.cases():
    suite.check(impl, invariant)   # 失败即抛,定位到具体格子
# 或:suite.run() 收集全部结果(不抛);suite.passed() 便捷判全过

要点:

  • 不变量 = (实现实例) -> None,通过则正常返回、违反则抛异常;只验外部可观测行为;
  • 每个格子都新建实例(工厂无参),杜绝实现间状态串味;
  • cases() 返回 (实现名, 不变量名) 列表,可直接喂 pytest.mark.parametrize; ids() 给对齐的可读 id(形如 impl/invariant);
  • 这正是"敢放手让第三方填广度、却让脊柱不变量烂不掉"的落点:没过 conformance 的实现直接 CI 红,而非生产事故。

On this page