Add Stopgap handling of cfg files in cfg-editor
Basic parsing and writing of python config files. Does not preserve comments, can't transform the old format to the new one. This is just so the executable that is delivered actually does something with the new config files. Change-Id: I4bb8310e1af7a05f90dd426dfa629080583aff66 Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30935 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
This commit is contained in:
@ -29,6 +29,9 @@ from os import path
|
||||
# Add import path for inplace usage
|
||||
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
|
||||
|
||||
import logging
|
||||
from mlzlog import ColoredConsoleHandler
|
||||
|
||||
from frappy.gui.qt import QApplication
|
||||
from frappy.gui.cfg_editor.mainwindow import MainWindow
|
||||
|
||||
@ -38,7 +41,11 @@ def main(argv=None):
|
||||
parser.add_argument('-f', '--file', help='Configuration file to open.')
|
||||
args = parser.parse_args()
|
||||
app = QApplication(argv)
|
||||
window = MainWindow(args.file)
|
||||
logger = logging.getLogger('gui')
|
||||
console = ColoredConsoleHandler()
|
||||
console.setLevel(logging.INFO)
|
||||
logger.addHandler(console)
|
||||
window = MainWindow(args.file, log=logger)
|
||||
window.show()
|
||||
return app.exec()
|
||||
|
||||
|
@ -24,6 +24,8 @@ import configparser
|
||||
from collections import OrderedDict
|
||||
from configparser import NoOptionError
|
||||
|
||||
from frappy.config import load_config
|
||||
from frappy.datatypes import StringType, EnumType
|
||||
from frappy.gui.cfg_editor.tree_widget_item import TreeWidgetItem
|
||||
from frappy.gui.cfg_editor.utils import get_all_children_with_names, \
|
||||
get_all_items, get_interface_class_from_name, get_module_class_from_name, \
|
||||
@ -41,7 +43,7 @@ SECTIONS = {NODE: 'description',
|
||||
MODULE: 'class'}
|
||||
|
||||
|
||||
def write_config(file_name, tree_widget):
|
||||
def write_legacy_config(file_name, tree_widget):
|
||||
itms = get_all_items(tree_widget)
|
||||
itm_lines = OrderedDict()
|
||||
value_str = '%s = %s'
|
||||
@ -79,8 +81,7 @@ def write_config(file_name, tree_widget):
|
||||
with open(file_name, 'w', encoding='utf-8') as configfile:
|
||||
configfile.write('\n'.join(itm_lines.values()))
|
||||
|
||||
|
||||
def read_config(file_path):
|
||||
def read_legacy_config(file_path):
|
||||
# TODO datatype of params and properties
|
||||
node = TreeWidgetItem(NODE)
|
||||
ifs = TreeWidgetItem(name='Interfaces')
|
||||
@ -147,6 +148,119 @@ def read_config(file_path):
|
||||
node = get_comments(node, ifs, mods, file_path)
|
||||
return node, ifs, mods
|
||||
|
||||
def fmt_value(param, dt):
|
||||
if isinstance(dt, StringType):
|
||||
return repr(param)
|
||||
if isinstance(dt, EnumType):
|
||||
try:
|
||||
return int(param)
|
||||
except ValueError:
|
||||
return repr(param)
|
||||
return param
|
||||
|
||||
def fmt_param(param, pnp):
|
||||
props = pnp[param.name]
|
||||
if isinstance(props, list):
|
||||
dt = props[0].datatype
|
||||
else:
|
||||
dt = props.datatype
|
||||
|
||||
if param.childCount() > 1 or (param.childCount() == 1 and param.child(0).name != 'value'):
|
||||
values = []
|
||||
main_value = param.get_value()
|
||||
if main_value:
|
||||
values.append(fmt_value(main_value, dt))
|
||||
for i in range(param.childCount()):
|
||||
prop = param.child(i)
|
||||
propdt = props[1][prop.name].datatype
|
||||
propv = fmt_value(prop.get_value(), propdt)
|
||||
values.append(f'{prop.name} = {propv}')
|
||||
values = f'Param({", ".join(values)})'
|
||||
else:
|
||||
values = fmt_value(param.get_value(), dt)
|
||||
return f' {param.name} = {values},'
|
||||
|
||||
def write_config(file_name, tree_widget):
|
||||
"""stopgap python config writing. assumes no comments are in the cfg."""
|
||||
itms = get_all_items(tree_widget)
|
||||
for itm in itms:
|
||||
if itm.kind == 'comment':
|
||||
print('comments are broken right now. not writing a file. exiting...')
|
||||
return
|
||||
lines = []
|
||||
root = tree_widget.topLevelItem(0)
|
||||
eq_id = root.name
|
||||
description = root.get_value()
|
||||
iface = root.child(0).child(0).name
|
||||
|
||||
lines.append(f'Node(\'{eq_id}\',\n {repr(description)},\n \'{iface}\',')
|
||||
for i in range(2, root.childCount()):
|
||||
lines.append(fmt_param(root.child(i), {}))
|
||||
lines.append(')')
|
||||
mods = root.child(1)
|
||||
for i in range(mods.childCount()):
|
||||
lines.append('\n')
|
||||
mod = mods.child(i)
|
||||
params_and_props = {}
|
||||
params_and_props.update(mod.properties)
|
||||
params_and_props.update(mod.parameters)
|
||||
descr = None
|
||||
for i in range(mod.childCount()):
|
||||
if mod.child(i).name == 'description':
|
||||
descr = mod.child(i)
|
||||
break
|
||||
lines.append(f'Mod(\'{mod.name}\',\n \'{mod.get_value()}\',\n \'{descr.get_value()}\',')
|
||||
for j in range(mod.childCount()):
|
||||
if j == i:
|
||||
continue
|
||||
lines.append(fmt_param(mod.child(j), params_and_props))
|
||||
lines.append(')')
|
||||
|
||||
with open(file_name, 'w', encoding='utf-8') as configfile:
|
||||
configfile.write('\n'.join(lines))
|
||||
|
||||
def read_config(file_path, log):
|
||||
config = load_config(file_path, log)
|
||||
node = TreeWidgetItem(NODE)
|
||||
ifs = TreeWidgetItem(name='Interfaces')
|
||||
mods = TreeWidgetItem(name='Modules')
|
||||
node.addChild(ifs)
|
||||
node.addChild(mods)
|
||||
nodecfg = config.pop('node', {})
|
||||
node.set_name(nodecfg['equipment_id'])
|
||||
node.set_value(nodecfg['description'])
|
||||
node.parameters = get_params(NODE)
|
||||
node.properties = get_props(NODE)
|
||||
|
||||
iface = TreeWidgetItem(INTERFACE, nodecfg['interface'])
|
||||
#act_class = get_interface_class_from_name(section_value)
|
||||
#act_item.set_class_object(act_class)
|
||||
ifs.addChild(iface)
|
||||
for name, modcfg in config.items():
|
||||
act_item = TreeWidgetItem(MODULE, name)
|
||||
mods.addChild(act_item)
|
||||
cls = modcfg.pop('cls')
|
||||
act_item.set_value(cls)
|
||||
act_class = get_module_class_from_name(cls)
|
||||
act_item.set_class_object(act_class)
|
||||
act_item.parameters = get_params(act_class)
|
||||
act_item.properties = get_props(act_class)
|
||||
for param, options in modcfg.items():
|
||||
if not isinstance(options, dict):
|
||||
prop = TreeWidgetItem(PROPERTY, param, str(options))
|
||||
act_item.addChild(prop)
|
||||
else:
|
||||
param = TreeWidgetItem(PARAMETER, param)
|
||||
param.set_value('')
|
||||
act_item.addChild(param)
|
||||
for k, v in options.items():
|
||||
if k == 'value':
|
||||
param.set_value(str(v))
|
||||
else:
|
||||
param.addChild(TreeWidgetItem(PROPERTY, k, str(v)))
|
||||
#node = get_comments(node, ifs, mods, file_path)
|
||||
return node, ifs, mods
|
||||
|
||||
|
||||
def get_value(config, section, option):
|
||||
value = config.get(section, option)
|
||||
|
@ -39,9 +39,10 @@ COMMENT = 'comment'
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
def __init__(self, file_path=None, parent=None):
|
||||
def __init__(self, file_path=None, log=None, parent=None):
|
||||
super().__init__(parent)
|
||||
loadUi(self, 'mainwindow.ui')
|
||||
self.log = log
|
||||
self.tabWidget.currentChanged.connect(self.tab_relevant_btns_disable)
|
||||
if file_path is None:
|
||||
self.tab_relevant_btns_disable(-1)
|
||||
@ -179,7 +180,7 @@ class MainWindow(QMainWindow):
|
||||
QMessageBox.StandardButton.Save)
|
||||
|
||||
def new_node(self, name, file_path=None):
|
||||
node = NodeDisplay(file_path)
|
||||
node = NodeDisplay(file_path, self.log)
|
||||
if node.created:
|
||||
node.tree_widget.currentItemChanged.connect(self.disable_btns)
|
||||
self.tabWidget.setCurrentIndex(self.tabWidget.addTab(node, name))
|
||||
|
@ -26,10 +26,12 @@ from frappy.gui.cfg_editor.utils import loadUi
|
||||
|
||||
|
||||
class NodeDisplay(QWidget):
|
||||
def __init__(self, file_path=None, parent=None):
|
||||
def __init__(self, file_path=None, log=None, parent=None):
|
||||
super().__init__(parent)
|
||||
loadUi(self, 'node_display.ui')
|
||||
self.log = log
|
||||
self.saved = bool(file_path)
|
||||
self.tree_widget.log = log
|
||||
self.created = self.tree_widget.set_file(file_path)
|
||||
self.tree_widget.save_status_changed.connect(self.change_save_status)
|
||||
self.tree_widget.currentItemChanged.connect(self.set_scroll_area)
|
||||
|
@ -99,8 +99,8 @@ def get_file_paths(widget, open_file=True):
|
||||
dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave)
|
||||
dialog.setFileMode(QFileDialog.FileMode.AnyFile)
|
||||
dialog.setWindowTitle(title)
|
||||
dialog.setNameFilter('*.cfg')
|
||||
dialog.setDefaultSuffix('.cfg')
|
||||
dialog.setNameFilter('*.py')
|
||||
dialog.setDefaultSuffix('.py')
|
||||
dialog.exec()
|
||||
return dialog.selectedFiles()
|
||||
|
||||
|
@ -102,7 +102,7 @@ class TreeWidget(QTreeWidget):
|
||||
self.file_path = file_path
|
||||
if self.file_path:
|
||||
if os.path.isfile(file_path):
|
||||
self.set_tree(read_config(self.file_path))
|
||||
self.set_tree(read_config(self.file_path, self.log))
|
||||
self.emit_save_status_changed(True)
|
||||
return True
|
||||
self.file_path = None
|
||||
@ -277,7 +277,7 @@ class TreeWidget(QTreeWidget):
|
||||
file_name = self.file_path
|
||||
if not self.file_path or save_as:
|
||||
file_name = get_file_paths(self, False)[-1]
|
||||
if file_name[-4:] == '.cfg':
|
||||
if file_name[-3:] == '.py':
|
||||
self.file_path = file_name
|
||||
write_config(self.file_path, self)
|
||||
self.emit_save_status_changed(True)
|
||||
|
@ -228,7 +228,7 @@ def get_widget(datatype, readonly=False, parent=None):
|
||||
TupleOf: TupleWidget,
|
||||
StructOf: StructWidget,
|
||||
ArrayOf: ArrayWidget,
|
||||
}.get(datatype.__class__)(datatype, readonly, parent)
|
||||
}.get(datatype.__class__, TextWidget)(datatype, readonly, parent)
|
||||
# TODO: handle NoneOr
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user