101 lines
4.0 KiB
Python
101 lines
4.0 KiB
Python
#!/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()
|