"""包基线冒烟测试:可导入、版本号存在。""" from pathlib import Path import polygateway def test_package_importable_with_version() -> None: import tomllib declared = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"] assert polygateway.__version__ == declared # 单一版本源: 与 pyproject 同步 def test_ocr_public_surface_exported(): """M3 OCR 公共 API 面(设计 §3;transport 结果与 Protocol 不出顶层)。""" import polygateway for name in ( "OcrClient", "OcrSettings", "OcrTextResult", "OcrLayoutResult", "OcrLayoutElement", ): assert hasattr(polygateway, name), name assert name in polygateway.__all__, name def test_telemetry_schema_sql_exported(): """issue #13: manual 档下游需要主动索取"库要求的最小 schema"的顶层入口。 同时钉住公共面**只增这一个名字**: `missing_columns_warning` 是 recorder 内部 共用的文案构造函数,导出它等于多一份永久承诺(库承诺公共面只增不删)。 """ assert "telemetry_schema_sql" in polygateway.__all__ assert callable(polygateway.telemetry_schema_sql) assert "missing_columns_warning" not in polygateway.__all__ assert not hasattr(polygateway, "missing_columns_warning") def test_telemetry_status_exported(): """issue #15: `client.telemetry_status` 的返回类型必须能从顶层 import。 下游对账/告警要给这个快照做类型标注,若只在 `polygateway.types` 里,标注就得 深入子模块,而本库的约定是「顶层导出即公共 API 面」。`TelemetryStatusProvider` 则**不**导出: 它是端口,库外无实现者,导出即多一份永久承诺。 """ assert "TelemetryStatus" in polygateway.__all__ assert polygateway.TelemetryStatus is not None assert "TelemetryStatusProvider" not in polygateway.__all__ def test_thinking_public_surface_exported(): """issue #16/#17: 推理决策搬进 `polygateway.thinking` 后,公共符号必须走顶层。 搬模块本身会断掉 `from polygateway.providers import ThinkingCapability` 这类 深路径 import。给下游一个稳定引用点,是以后再重组不再破坏下游的前提——本库 的约定是「顶层导出即公共 API 面」。 `observe_thinking` / `reconcile_thinking` **不**导出: 它们是 transport 内部 的裁定与对账,下游读 `LLMResponse.thinking_observation` 即可,导出即多一份 永久承诺。`ThinkingResolution` 则**要**导出——它是已导出的 `resolve_thinking` 的返回类型,不导出等于下游拿得到实例却写不出类型标注。 """ for name in ( "ThinkingCapability", "ThinkingObservation", "ThinkingResolution", "ThinkingUnsupportedError", "ThinkingWire", "get_capability", "register_capability", "resolve_thinking", ): assert hasattr(polygateway, name), name assert name in polygateway.__all__, name assert "observe_thinking" not in polygateway.__all__ assert "reconcile_thinking" not in polygateway.__all__ def test_every_promised_export_is_actually_importable(): """`__all__` 里的每个名字都必须真的绑在包上。 只维护 `__all__` 而漏掉 import,`from polygateway import X` 与 `import *` 都会当场炸,而逐个点名的用例只覆盖它当时想到的符号——2026-09-04 的 `ThinkingWire` 正是这样漏进来的(在 `__all__` 里躺了一个提交却 import 不到)。 """ missing = [name for name in polygateway.__all__ if not hasattr(polygateway, name)] assert not missing, f"__all__ 承诺了但没绑上的符号: {missing}"