chronaxis.configuration.template_catalog
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""读取随包发布的合成场景模板;初始化命令与模板验收使用同一套资源。23目录中保存最小版和完整注释版YAML及小型合成输入。本模块仅提供有限模板清单4和文件内容,不创建用户目录、不执行分析、不把模板阈值当作真实设备参数。5"""6from dataclasses import dataclass7from importlib.resources import files8import json9from pathlib import PurePosixPath101112@dataclass(frozen=True)13class ConfigurationTemplate:14 """可选场景及其入口;名称用于CLI选择,说明同时注明合成数据和预期行为。"""15 name: str16 title: str17 config_type: str18 entrypoint: str19 expected: str202122def _catalog():23 """读取包内固定清单。参数: 无。返回: dict。异常: 缺失或损坏资源不隐藏。"""24 root=files('chronaxis.configuration').joinpath('templates')25 return root,json.loads(root.joinpath('catalog.json').read_text(encoding='utf-8'))262728def available_templates():29 """列出当前所有场景。参数: 无。返回: ConfigurationTemplate tuple。异常: 包资源错误。"""30 _,catalog=_catalog()31 return tuple(ConfigurationTemplate(item['name'],item['title'],item['config_type'],32 item['entrypoint'],item['expected']) for item in catalog['templates'])333435def _relative_path(text):36 """限制包内及新目录内的相对路径。参数: 文本。返回: PurePosixPath。异常: ValueError。3738 清单由项目维护;仍拒绝绝对路径、返回父目录和Windows反斜线,防止资源误配越界。39 """40 path=PurePosixPath(text)41 if not text or not path.parts or '\\' in text or ':' in text or path.is_absolute() or '..' in path.parts:42 raise ValueError('模板资源必须使用目录内的相对路径')43 return path444546def template_files(name,*,style='annotated'):47 """取得一个场景的完整文件集。参数: 场景名、minimal/annotated。返回: (相对路径,bytes) tuple。4849 异常: 未知场景/风格为ValueError,包内文件错误直接传播;不读取用户配置或写文件。50 两种风格只有注释不同,批量子计划也按同一风格选择。资源不含环境变量或模板执行。51 """52 if style not in ('minimal','annotated'):53 raise ValueError('模板风格需要minimal或annotated')54 root,catalog=_catalog()55 match=next((item for item in catalog['templates'] if item['name']==name),None)56 if match is None:57 raise ValueError('未知配置场景:'+str(name))58 entries=[dict(source=name+'/'+style+'.yaml',target=match['entrypoint']),*match['files']]59 result=[]60 targets=set()61 for item in entries:62 source=_relative_path(item['source'].replace('{style}',style))63 target=_relative_path(item['target'])64 if target.as_posix().casefold() in targets:65 raise ValueError('模板输出路径重复:'+str(target))66 targets.add(target.as_posix().casefold())67 result.append((target.as_posix(),root.joinpath(*source.parts).read_bytes()))68 return tuple(result)69