Files
AIO_3D_Print_Web_Platform/app/conf_parse.py

163 lines
7.1 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.

import configparser
import json
import copy
import math
class ConfParse:
def __init__(self, config_def_json_files_paths):
self.config_def_json_files_paths = config_def_json_files_paths
self.configs = {}
for file in self.config_def_json_files_paths:
with open(file, 'r') as f:
jf = json.load(f)
if "settings" in jf:
setting_json = jf["settings"]
for key, value in setting_json.items():
# print(key, value)
all_items = self._expend_children(value["children"])
for item_key, item_value in all_items.items():
self.configs[item_key] = item_value
elif "overrides" in jf:
override_json = jf["overrides"]
for key, value in override_json.items():
if key in self.configs:
for item_key, item_value in value.items():
self.configs[key][item_key] = item_value
else:
self.configs[key] = value
def _expend_children(self, config):
tmp_c = {}
for key,val in config.items():
if "children" in val:
tmp_c.update(self._expend_children(val["children"]))
val.pop("children", None)
tmp_c[key] = val
return tmp_c
def add_inst_cfg(self, inst_cfg_files_paths):
copy_settings = copy.deepcopy(self.configs)
config = configparser.ConfigParser()
for file in inst_cfg_files_paths:
config.read(file)
if config.has_section('values'):
for key, val in config.items('values'):
v = str(val)
if key not in copy_settings:
copy_settings[key] = {}
if v.startswith("="):
copy_settings[key]["value"] = v[1:]
else:
copy_settings[key]["value"] = v
return copy_settings
def parse_configs(self, settings):
class ConfigStr(str):
def __mul__(self, other): raise TypeError()
def __rmul__(self, other): raise TypeError()
def __add__(self, other): raise TypeError()
def __radd__(self, other): raise TypeError()
def __sub__(self, other): raise TypeError()
def __rsub__(self, other): raise TypeError()
def __truediv__(self, other): raise TypeError()
def __rtruediv__(self, other): raise TypeError()
def __pow__(self, other): raise TypeError()
def __rpow__(self, other): raise TypeError()
parsed_settings = copy.deepcopy(settings)
last_unparsed = -1
while True:
unparsed = 0
# 构建上下文环境变量上下文用作eval的变量替换
context = {}
for k, v in parsed_settings.items():
# 上下文里的变量取值:优先使用 value如果有否则使用 default_value
if "value" in v:
val = v["value"]
elif "default_value" in v:
val = v["default_value"]
else:
val = None
if isinstance(val, str):
if val.lower() == "true":
val = True
elif val.lower() == "false":
val = False
else:
try:
val = int(val)
except ValueError:
try:
val = float(val)
except ValueError:
val = ConfigStr(val)
context[k] = val
# 自定义函数实现
def resolveOrValue(key):
return context.get(key)
def extruderValues(key):
# 兼容简易的多挤出机查询逻辑,目前单挤出机环境下返回一个单元素列表
return [context.get(key)]
def extruderValue(extruder_position, key):
# 对于单挤出机环境或者全局配置,直接忽略 extruder_position返回指定的 key 对应的值
return context.get(key)
def defaultExtruderPosition():
return 0
# 提供基础的运算函数支持
builtin_funcs = {
"max": max,
"min": min,
"abs": abs,
"round": round,
"int": int,
"float": float,
"bool": bool,
"math": math,
"resolveOrValue": resolveOrValue,
"extruderValues": extruderValues,
"extruderValue": extruderValue,
"defaultExtruderPosition": defaultExtruderPosition
}
for key, val_dict in parsed_settings.items():
for field, field_val in val_dict.items():
# 仅对字符串进行尝试计算
if "type" == field:
continue
if isinstance(field_val, str):
try:
# 如果是一个普通的纯字符串,比如分类名(如"Machine Type" eval可能会抛出SyntaxError或NameError
# 如果它是一个python表达式则会被顺利计算出结果
evaluated = eval(field_val, {"__builtins__": builtin_funcs}, context)
# 避免将原本只是用来作类型声明的 "int"/"float" 纯字符串,被错误求值为内置 Python type class 打断 JSON 序列化
if evaluated != field_val and not isinstance(evaluated, type):
if val_dict.get("type") == "str" and not isinstance(evaluated, str):
if isinstance(evaluated, (list, dict)):
import json
val_dict[field] = json.dumps(evaluated).replace(" ", "")
else:
val_dict[field] = str(evaluated)
else:
val_dict[field] = evaluated
except Exception:
# 解析失败(例如是个普通英文字符串或者依赖还没被解开)则暂不做处理
unparsed += 1
# 如果在这一轮中未解析出的表达式数量不再减少,说明已经到达极限,跳出循环
if unparsed == last_unparsed:
break
last_unparsed = unparsed
return parsed_settings