pbl_appcodes/pbl_appcodes/codes_data.py

139 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
pbl_appcodes.codes_data —— codes.json 装载与数量契约常量
唯一事实源modules/pbl_appcodes/pbl_appcodes/codes.json
设计文档projects/pbls/docs/01-design/appcodes.md
"""
import json
import os
HERE = os.path.dirname(os.path.abspath(__file__))
CODES_PATH = os.path.join(HERE, 'codes.json')
# ---- 数量契约硬编码常量self_check 据此校验实际数据)----
GROUP_COUNT = 8 # MAIN_GROUPS(6) + EXTRA_GROUPS(2)
ITEM_COUNT = 74
DIALECT = 'mariadb'
MAIN_GROUP_COUNT = 6
EXTRA_GROUP_COUNT = 2
# 主组6蓝图类型 / 蓝图状态 / 质量等级 / 校验维度 / 子对象类型 / Agent 工具
MAIN_GROUP_CODES = (
'pbl_blueprint_type',
'pbl_blueprint_status',
'pbl_quality_level',
'pbl_validation_dim',
'pbl_subobject_type',
'pbl_agent_tool',
)
# 扩展组2证据类型 / 量规等级
EXTRA_GROUP_CODES = (
'pbl_evidence_type',
'pbl_assessment_rubric_level',
)
_CACHE = {'meta': None, 'groups': None, 'path': None, 'mtime': None}
def load_codes(path=None, force=False):
"""
装载 codes.json返回 (meta, groups)。
带 mtime 缓存:文件未变不重复解析(应用启动后高频调用)。
"""
path = path or CODES_PATH
try:
mtime = os.path.getmtime(path)
except OSError:
mtime = None
if (not force and _CACHE['groups'] is not None
and _CACHE['path'] == path and _CACHE['mtime'] == mtime):
return _CACHE['meta'], _CACHE['groups']
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
if isinstance(data, list):
meta, groups = {}, data
else:
meta = data.get('_meta') or {}
groups = None
for key in ('groups', 'codes', 'appcodes', 'data', 'items'):
val = data.get(key)
if isinstance(val, list) and val:
groups = val
break
if groups is None:
groups = []
_CACHE.update({'meta': meta, 'groups': groups, 'path': path, 'mtime': mtime})
return meta, groups
def _reload():
return load_codes(force=True)
CODES_META, ALL_GROUPS = load_codes()
# 主组 / 扩展组切片(按 code 归属划分,顺序保持 codes.json 原序)
MAIN_GROUPS = [g for g in ALL_GROUPS if g.get('code') in MAIN_GROUP_CODES]
EXTRA_GROUPS = [g for g in ALL_GROUPS if g.get('code') in EXTRA_GROUP_CODES]
def group_items(group):
"""取组内项数组(兼容 items/children/codes/options 键名)"""
if not isinstance(group, dict):
return []
for key in ('items', 'children', 'codes', 'options', 'values', 'entries'):
val = group.get(key)
if isinstance(val, list):
return val
return []
def iter_items(groups=None):
"""迭代 (group_code, group_name, item) 三元组"""
groups = ALL_GROUPS if groups is None else groups
for g in groups:
gcode = g.get('code') or ''
gname = g.get('name') or ''
for it in group_items(g):
yield gcode, gname, it
def group_codes(groups=None):
"""组编码有序列表"""
groups = ALL_GROUPS if groups is None else groups
return [g.get('code') for g in groups]
def all_item_codes(group_code=None):
"""项编码列表(可按组过滤)"""
out = []
for gcode, _gname, it in iter_items():
if group_code is None or gcode == group_code:
out.append(it.get('code'))
return out
def find_group(group_code):
"""按组编码取组 dict未找到返回 None"""
for g in ALL_GROUPS:
if g.get('code') == group_code:
return g
return None
def counts():
"""实测数量:{'groups': n, 'items': m, 'main': x, 'extra': y}"""
return {
'groups': len(ALL_GROUPS),
'items': sum(len(group_items(g)) for g in ALL_GROUPS),
'main': len(MAIN_GROUPS),
'extra': len(EXTRA_GROUPS),
'dialect': (CODES_META or {}).get('dialect'),
}