| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- r"""重建/查看"台账等价验收"的**基线**(2026-09-18 现场问题驱动)。
- ## 为什么需要它
- `rebuild_all.py` 最后一步跑 `rebuild_from_raw.py --verify`:拿当前产物与**基线**逐值比对,
- 证明"重算能复现同一批数字"。基线是 `outputs/<场>/windscada/_pre_rebuild_20260911/` 下的 4 件
- (`alarms` / `workorders` / `oil_samples_index` / `temp_monthly`)。
- **2026-09-17 用户令「清除产物」把它一并真删了**(该命令不留备份)⇒ 之后每次重算最后一步都报
- `rc=5 找不到随包基线 ⇒ 无法做等价验收("没验收"不是"通过")`,门户上就显示成"重算失败"。
- 本器把"重建基线"变成一条命令:在当前产物**已核实无误**的前提下快照这 4 件,并写清来历。
- ## 用法
- python scripts/set_baseline.py --check # 看基线在不在(不看盘面以外的推断)
- python scripts/set_baseline.py # 用**当前在位产物**快照成基线(同路径, 覆盖)
- 退出码: 0 成功/在位 · 2 缺源件
- """
- from __future__ import annotations
- import argparse
- import datetime as dt
- import json
- import pathlib
- import shutil
- import sys
- ROOT = pathlib.Path(__file__).resolve().parents[1]
- sys.path.insert(0, str(ROOT))
- from src import paths as P # noqa: E402
- FILES = ('alarms.parquet', 'workorders.parquet', 'oil_samples_index.parquet', 'temp_monthly.parquet')
- BASE_NAME = '_pre_rebuild_20260911'
- def base_dir(farm: str | None = None) -> pathlib.Path:
- return P.store(farm) / BASE_NAME
- def main() -> int:
- ap = argparse.ArgumentParser(description='重建/查看 台账等价验收基线')
- ap.add_argument('--check', action='store_true', help='只看基线在不在')
- ap.add_argument('--farm', default=None)
- a = ap.parse_args()
- farm = a.farm or P.farm()
- store = P.store(farm)
- b = base_dir(farm)
- have = {n: (b / n) for n in FILES}
- print(f'== 等价验收基线 · {P.rel(b)} ==')
- for n, p in have.items():
- print(f' [{"OK " if p.is_file() else "缺 "}] {n:28s}'
- + (f' {p.stat().st_size:>12,} B' if p.is_file() else ''))
- if a.check:
- ok = all(p.is_file() for p in have.values())
- print(f' 结论: {"基线在位, 重算最后一步可做等价验收" if ok else "基线缺失 ⇒ 重算最后一步会 rc=5(没验收); 跑本命令(不带 --check)重建"}')
- return 0 if ok else 2
- miss = [n for n, p in have.items() if not (store / n).is_file()]
- if miss:
- print(f' [X] 当前产物里缺 {miss} —— 先重算产出它们, 再建基线')
- return 2
- b.mkdir(parents=True, exist_ok=True)
- for n in FILES:
- shutil.copy2(store / n, b / n)
- (b / '_来源说明.json').write_text(json.dumps(dict(
- why='rebuild_all 最后一步「台账等价验收」要一份标准答案做逐值比对; 基线目录被「清除产物」真删后, '
- '该步 rc=5「没验收」⇒ 门户上显示重算失败。',
- what='本目录 4 件 = 快照时**在位且已核实**的产物(alarms/workorders/oil_samples_index/temp_monthly)。',
- nature='★ 这是**回归基线**(证明将来的重算能复现同一批数字),不是历史交付基线。',
- built_at=dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- rebuilt_by='scripts/set_baseline.py',
- verify_by='python scripts/rebuild_from_raw.py --verify(全部通过即基线有效)',
- ), ensure_ascii=False, indent=1) + '\n', encoding='utf-8')
- print(f' 已重建基线: {P.rel(b)}(4 件 + _来源说明.json)')
- print(' 复验: python scripts/rebuild_from_raw.py --verify')
- return 0
- if __name__ == '__main__':
- for _s in (sys.stdout, sys.stderr):
- try:
- _s.reconfigure(errors='replace')
- except Exception:
- pass
- sys.exit(main())
|