Chronaxis用户手册English
本页目录

chronaxis.configuration.diagnostics

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""为配置错误附上原文位置与有限的上下文;成功计划不保存此处的文档对象。23这里只消费已解析的原生值,不重新读取配置或来源。字段路径采用带引号键的4JSON路径;不存在字段回指最近所属对象,不能给缺少的值捏造行列。5"""6import json7import re89from .models import field_path_text101112def field_path_parts(text):13    """读取内部字段路径。参数: $开头文本。返回: tuple或无法定位时None。异常: 无。1415    引号键用标准JSON解码,不执行表达式;组合诊断如$.signals/derived不能冒充字段。16    """17    if not isinstance(text,str) or not text.startswith('$'):18        return None19    parts=[]20    position=121    while position<len(text):22        if text[position]=='.':23            match=re.match(r'[^.\[\]/]+',text[position+1:])24            if match is None:25                return None26            parts.append(match[0])27            position+=len(match[0])+128        elif text[position:position+2]=='["':29            try:30                key,end=json.JSONDecoder().raw_decode(text,position+1)31            except ValueError:32                return None33            if type(key) is not str or text[end:end+1]!=']':34                return None35            parts.append(key)36            position=end+137        else:38            match=re.match(r'\[(0|[1-9][0-9]*)\]',text[position:])39            if match is None:40                return None41            parts.append(int(match[1]))42            position+=len(match[0])43    return tuple(parts)444546def child_path(path,key):47    """追加一层真实键。参数: 字段路径/字符串键。返回: 无歧义路径。异常: 内部路径不合法。48    """49    return path+field_path_text((key,))[1:]505152def value_preview(value):53    """只显示有限值摘要。参数: JSON原生值。返回: 最多180字符。异常: 无。5455    容器仅报类型/大小,防止错误输出整份配置、内存行或自由元数据。56    """57    if type(value) is dict:58        return f'对象({len(value)}个字段)'59    if type(value) is list:60        return f'数组({len(value)}项)'61    text=json.dumps(value,ensure_ascii=False,allow_nan=False)62    return text if len(text)<=180 else text[:177]+'…'636465def locate_error(error,document):66    """给计划异常补充有限诊断字段。参数: 计划异常/原文档。返回: 同一异常。异常: 无。6768    不保存document、原字典或位置表;只复制源码名、单一位置、对象名和短值。69    """70    # 集合的每项分别通过导入来源表定位,不把首项位置套到整份报告。71    if getattr(error, '_diagnostics', None) is not None:72        for item in error.diagnostics:73            locate_error(item, document)74        first = error.diagnostics[0]75        for name in ('path','source','location','object_name','value_preview','hint'):76            setattr(error, name, getattr(first, name))77        error.refresh_text()78        return error79    # 导入器可能已经把异常定位到另一个文件;外层不得用主文件覆盖真实来源。80    if error.source is not None:return error81    parts=field_path_parts(error.path)82    error.source=document.source83    if parts is None:84        error.refresh_text()85        return error86    error.location=document.location_for(parts)87    current=document.data88    name=None89    labels={'signals':'信号','sources':'来源','rules':'规则','windows':'窗口',90            'calculations':'计算项','sequences':'序列','jobs':'任务','presets':'预设'}91    label=next((labels[part] for part in parts if part in labels),'对象')92    # 从根走向出错字段,最近的命名对象比根dataset更能解释该处声明。93    missing=False94    for part in (*parts,None):95        if type(current) is dict:96            candidate=current.get('name')97            if type(candidate) is str:98                name=candidate[:120]99        if part is None:100            break101        if type(current) is dict and type(part) is str and part in current:102            current=current[part]103        elif type(current) is list and type(part) is int and part<len(current):104            current=current[part]105        else:106            missing=True107            break108    error.object_name=None if name is None else label+' '+name109    error.value_preview='未提供' if missing else value_preview(current)110    origin=document.origin_for(parts)111    if origin is not None:112        error.source=origin.source113        error.path=field_path_text(origin.field_path)114        error.location=origin.location115    error.refresh_text()116    return error117
Chronaxis 用户手册 · 离线阅读