#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import annotations import sys from pathlib import Path EXPECTED_PROJECT_VERSION = "0.4.6" EXPECTED_RUNTIME_VERSION = "0.4.6-production-spatial-candidate-query" EXPECTED_BUILDER = "cm95pbf-builder/0.4.6-spatial-candidate-query" def fail(msg: str) -> None: print(f"FAIL: {msg}") raise SystemExit(2) def main() -> None: root = Path.cwd() pyproject = root / "pyproject.toml" init_py = root / "src" / "cm95pbf" / "__init__.py" builder_py = root / "src" / "cm95pbf" / "builder.py" production_py = root / "src" / "cm95pbf" / "production.py" japan_policy = root / "config" / "pbf" / "cm95_tile_policy_japan_full_detail_v1.yaml" japan_disp = root / "config" / "mappings" / "cm95_gap_disposition_japan_dataset_1_v1.yaml" for path in (pyproject, init_py, builder_py, production_py, japan_policy, japan_disp): if not path.exists(): fail(f"缺少文件: {path}") pyproject_text = pyproject.read_text(encoding="utf-8") if f'version = "{EXPECTED_PROJECT_VERSION}"' not in pyproject_text: fail(f"pyproject 不是 {EXPECTED_PROJECT_VERSION}") init_text = init_py.read_text(encoding="utf-8") if EXPECTED_RUNTIME_VERSION not in init_text: fail("runtime version 不正确") if EXPECTED_BUILDER not in init_text: fail("builder contract 不正确") builder_text = builder_py.read_text(encoding="utf-8") required_fragments = [ "chart_point_geometry\", \"spx_point_geom", "chart_line_geometry\", \"spx_line_geom", "chart_area_geometry\", \"spx_area_geom", "FORCE INDEX ({spatial_index})", "STRAIGHT_JOIN chart_feature f ON f.id=g.feature_id", "MBRIntersects(", "geom_rows.sort(", "chart_sounding_point s FORCE INDEX (spx_sounding_geom)", "STRAIGHT_JOIN chart_feature f ON f.id=s.feature_id", "MBRContains(", "out.sort(", ] for fragment in required_fragments: if fragment not in builder_text: fail(f"builder 缺少 v1.4.6 query contract: {fragment}") # The expensive feature fetch SQL must no longer contain DB-side ORDER BY. start = builder_text.index("def _fetch_scale_features") end = builder_text.index("def _fetch_scale_soundings", start) if "ORDER BY" in builder_text[start:end]: fail("_fetch_scale_features 仍包含 SQL ORDER BY") start2 = builder_text.index("def _fetch_scale_soundings") end2 = builder_text.index("def _compose_navigation_aids", start2) if "ORDER BY" in builder_text[start2:end2]: fail("_fetch_scale_soundings 仍包含 SQL ORDER BY") production_text = production_py.read_text(encoding="utf-8") if '"builder_contract_version": BUILDER_CONTRACT_VERSION' not in production_text: fail("production plan hash 未纳入 builder_contract_version") try: import cm95pbf except Exception as exc: fail(f"无法 import 已安装 cm95pbf: {exc}") if getattr(cm95pbf, "__version__", None) != EXPECTED_RUNTIME_VERSION: fail(f"installed runtime={getattr(cm95pbf, '__version__', None)!r}") if getattr(cm95pbf, "BUILDER_CONTRACT_VERSION", None) != EXPECTED_BUILDER: fail(f"installed builder={getattr(cm95pbf, 'BUILDER_CONTRACT_VERSION', None)!r}") print("CM95 PBF v1.4.6 preflight") print("=" * 72) print(f"Project version : {EXPECTED_PROJECT_VERSION} PASS") print(f"Runtime version : {EXPECTED_RUNTIME_VERSION} PASS") print(f"Builder contract : {EXPECTED_BUILDER} PASS") print("Feature query spatial-first : PASS") print("POINT/LINE/AREA spatial idx : PASS") print("Feature SQL ORDER BY removed : PASS") print("Python deterministic sort : PASS") print("Sounding spatial-first : PASS") print("Plan hash builder binding : PASS") print("Japan G=7500 policy present : PASS") print("OVERALL : PASS") if __name__ == "__main__": main()