lpcmanager

Variable Options : fixed parsing, add On Load fix
som6
2020-11-12, Edouard Tisserant
fecb8381e105
Parents 878b58a39717
Children e19831529c8c
Variable Options : fixed parsing, add On Load fix
- fixed parsing to deal with dblquotes and old bugs better, use intermediate representation once parsed, and add function to generate options string from that representation,
- add On Load fix to be backward compatible with previous options syntax and onchange column
--- a/LPCExtension.py Thu Nov 05 14:31:30 2020 +0100
+++ b/LPCExtension.py Thu Nov 12 11:02:32 2020 +0100
@@ -105,8 +105,21 @@
#
# --------- special OnChange behavior ------------
+# ----- on load options and OnChange colums fix --------
#
from py_ext.PythonFileCTNMixin import PythonFileCTNMixin
-from OnChangeFromOptions import GetVarOnChangeContent
+from OnChangeFromOptions import GetVarOnChangeContent, FixOptions
PythonFileCTNMixin.GetVarOnChangeContent = GetVarOnChangeContent
+
+old_PythonFileCTNMixin__init__ = PythonFileCTNMixin.__init__
+def PythonFileCTNMixin__init__with_FixOptions(self):
+ old_PythonFileCTNMixin__init__(self)
+ FixOptions(self)
+
+PythonFileCTNMixin.__init__ = PythonFileCTNMixin__init__with_FixOptions
+
+
+
+
+
--- a/OnChangeFromOptions.py Thu Nov 05 14:31:30 2020 +0100
+++ b/OnChangeFromOptions.py Thu Nov 12 11:02:32 2020 +0100
@@ -3,25 +3,38 @@
from __future__ import absolute_import
-from OptionsParsing import ParseOptions
+from OptionsParsing import ParseOptions, GenOptions
@staticmethod
def GetVarOnChangeContent(var):
- opts = variable.getopts()
- parsed_opts = re.findall(opt_parser,opts)
- needs_onChange = ('onchange', '') in parsed_opts
- if needs_onchange:
- existing_onchanges = [onchange.strip() for onchange in var.getonchange().split(',')]
- for unwanted in ["Alarm", "StoredValue"]:
- existing_onchanges.remove[unwanted]
-
- new_onchange = existing_onchange[:]
- if ('Static', '') in parsed_opts :
+ """
+ Function to overide the way PythonFileCTNMixin access OnChange column when
+ generating python code
+ """
+ opts = ParseOptions(var.getopts())
+ if opts.is_onchange:
+ new_onchange = [
+ onchange.strip() for onchange in var.getonchange().split(',')]
+ if opts.variable_type_selection == 1 : # "Static"
new_onchange += ["StoredValue"]
- elif ('Alarm', '') in parsed_opts :
+ elif opts.variable_type_selection == 3 : # "Alarm"
new_onchange += ["Alarm"]
return ','.join(new_onchange)
-
return var.getonchange()
+def FixOptions(self):
+ """
+ Function to be called at the end of PythonFileCTNMixin.__init__()
+ """
+ for var in self.CodeFile.variables.variable:
+ onchanges = [
+ onchange.strip() for onchange in var.getonchange().split(',')]
+ opts = ParseOptions(var.getopts())
+ for unwanted in ["Alarm", "StoredValue"]:
+ if unwanted in onchanges:
+ opts.is_onchange = True
+ onchanges.remove(unwanted)
+
+ var.setonchange(','.join(onchanges))
+ var.setopts(GenOptions(opts))
--- a/OptionsParsing.py Thu Nov 05 14:31:30 2020 +0100
+++ b/OptionsParsing.py Thu Nov 12 11:02:32 2020 +0100
@@ -4,31 +4,66 @@
import re
VARIABLETYPE = ["None", "Static", "Session", "Alarm"]
-opt_parser = re.compile(r'(\w+)\s*(?:=\s*"([^"]+)"\s*)?')
+opt_parser = re.compile(r'(\w+)\s*(?:=\s*"([^"]+)"\s*|=([^\s]+)\s*)?')
+
+class OptionsType(dict):
+ def __init__(self):
+ dict.__init__(self,
+ is_onchange = False,
+ is_scada = False,
+ is_static = False,
+ variable_type_selection = 0,
+ unit = None,
+ min = None,
+ max = None,
+ precision = None,
+ subgroup = None,
+ other = None,
+ tags = None)
+ self.__dict__ = self
+
+def GenOptions(opts):
+ options = VARIABLETYPE[opts.variable_type_selection]
+ if options == "None":
+ options = ""
+
+ if opts.is_onchange:
+ options += " onchange"
+
+ if opts.is_scada:
+ options += " scada"
+
+ if opts.is_static:
+ options += " static"
+
+ if opts.min is not None or opts.max is not None:
+ options += ' min="' + str(opts.min if opts.min is not None else 0) + '"'
+ options += ' max="' + str(opts.max if opts.min is not None else 0) + '"'
+
+ if opts.precision:
+ options += ' precision="' + str(opts.precision) + '"'
+
+ for name in ['subgroup', 'unit', 'other', 'tags']:
+ content = opts[name]
+ if content is not None:
+ options += ' ' + name + '="' + content + '"'
+
+ return options
def ParseOptions(opts):
- class AttrDict(dict):
- def __init__(self, *args, **kwargs):
- dict.__init__(self, *args, **kwargs)
- self.__dict__ = self
-
- res = AttrDict(
- is_onchange = False,
- is_scada = False,
- is_static = False,
- variable_type_selection = 0,
- unit = None,
- min = None,
- max = None,
- precision = None,
- subgroup = None,
- other = None,
- tags = None)
-
+ res = OptionsType()
+
options = re.findall(opt_parser,opts)
- for key,value in options:
+ for key,dblquote_value,smpl_value in options:
+
+ # sometime there is a dblquote at the end only of the value
+ # because of old bug in previous version, fix for backward compatibility
+ if len(smpl_value) > 0 and smpl_value[-1] == '"':
+ smpl_value = smpl_value[:-1]
+
+ value = dblquote_value+smpl_value
if value == "":
if key == "onchange":
res.is_onchange = True
--- a/WampOptionsEditor.py Thu Nov 05 14:31:30 2020 +0100
+++ b/WampOptionsEditor.py Thu Nov 12 11:02:32 2020 +0100
@@ -5,7 +5,7 @@
import controls
from collections import namedtuple
-from OptionsParsing import ParseOptions, VARIABLETYPE
+from OptionsParsing import ParseOptions, VARIABLETYPE, GenOptions, OptionsType
[ID_OPTIONSWIZARDDIALOG,ID_ONCHANGE,ID_OPTIONSTYPECHOICE,ID_SUBGROUPTEXT,ID_UNITTEXT,ID_VALUECHECKBOX,ID_MINSPIN,ID_MAXSPIN,ID_PRECISIONSPIN, ID_INITIALSPIN,ID_SCADACHECKBOX,ID_OTHERTEXT,ID_DESCRIPTION,ID_STATIC] = [wx.NewId() for _init_ctrls in range(14)]
@@ -220,28 +220,18 @@
def GetOptions(self):
- TypeSelected = self.OptionsTypeChoice.GetSelection()
- if TypeSelected<0:
- TypeSelected = 0
- options = VARIABLETYPE[TypeSelected]
- if options == "None":
- options = ""
+ opts = OptionsType()
- if self.OnChangeCheckbox.GetValue():
- options += " onchange"
-
- if self.ScadaCheckbox.GetValue():
- options += " scada"
-
- if self.StaticCheckbox.GetValue():
- options += " static"
+ opts.variable_type_selection = max(self.OptionsTypeChoice.GetSelection(), 0)
+ opts.is_onchange = self.OnChangeCheckbox.GetValue()
+ opts.is_scada = self.ScadaCheckbox.GetValue()
+ opts.is_static = self.StaticCheckbox.GetValue()
if self.MinSpin.IsEnabled():
- options += ' min="' + str(self.MinSpin.GetValue()) + '"'
- options += ' max="' + str(self.MaxSpin.GetValue()) + '"'
+ opts.min = self.MinSpin.GetValue()
+ opts.max = self.MaxSpin.GetValue()
- if self.PrecisionSpin.GetValue() != 0:
- options += ' precision=' + str(self.PrecisionSpin.GetValue()) + '"'
+ opts.precision = self.PrecisionSpin.GetValue()
for name, ctrl in [('subgroup', self.SubgroupText),
('unit', self.UnitText),
@@ -249,9 +239,10 @@
('tags', self.Tags)]:
content = ctrl.GetValue().encode('ascii','ignore')
if content:
- options += ' ' + name + '="' + content.translate(sanitizer, eraser) + '"'
+ opts[name] = content
- return options
+ return GenOptions(opts)
+
class WampOptionsCellControl(wx.PyControl):
@@ -301,6 +292,9 @@
def OnEditButtonClick(self, event):
# pop up the Duration Editor dialog
options = self.GetValue()
+ # backward compatibility
+
+
dialog = WampOptionsEditor(self.parent, options)
answer = dialog.ShowModal()
opt = dialog.GetOptions()
@@ -327,7 +321,7 @@
class WampOptionsCellEditor(wx.grid.PyGridCellEditor):
'''
- Grid cell editor that uses DurationCellControl to display an edit button.
+ Grid cell editor that uses WampOptionsCellControl to display an edit button.
'''
def __init__(self, table, row, col):