Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wxGUI: Export variables to Python in Graphical Modeler #3702

Merged
merged 12 commits into from
Jun 3, 2024
133 changes: 89 additions & 44 deletions gui/wxpython/gmodeler/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3333,6 +3333,12 @@ def __init__(self, fd, model, grassAPI="script"):
self._writePython()

def _getStandardizedOption(self, string):
"""Return GRASS standardized option based on specified string.

:param string: input string to be converted

:return: GRASS standardized option as a string or None if not converted
"""
if string == "raster":
return "G_OPT_R_MAP"
elif string == "vector":
Expand All @@ -3346,7 +3352,7 @@ def _getStandardizedOption(self, string):
elif string == "region":
return "G_OPT_M_REGION"

return ""
return None

def _writePython(self):
"""Write model to file"""
Expand Down Expand Up @@ -3390,7 +3396,8 @@ def _writePython(self):

modelItems = self.model.GetItems(ModelAction)
for item in modelItems:
for flag in item.GetParameterizedParams()["flags"]:
parametrizedParams = item.GetParameterizedParams()
for flag in parametrizedParams["flags"]:
if flag["label"]:
desc = flag["label"]
else:
Expand All @@ -3414,7 +3421,7 @@ def _writePython(self):
self.fd.write("# % answer: False\n")
self.fd.write("# %end\n")

for param in item.GetParameterizedParams()["params"]:
for param in parametrizedParams["params"]:
if param["label"]:
desc = param["label"]
else:
Expand All @@ -3441,6 +3448,29 @@ def _writePython(self):
self.fd.write("# % answer: {}\n".format(param["value"]))
self.fd.write("# %end\n")

# variables
for vname, vdesc in self.model.GetVariables().items():
self.fd.write("# %option")
optionType = self._getStandardizedOption(vdesc["type"])
if optionType:
self.fd.write(" {}".format(optionType))
self.fd.write("\n")
self.fd.write(
r"""# % key: {param_name}
# % description: {description}
# % required: yes
""".format(
param_name=vname,
description=vdesc.get("description", ""),
)
)
if optionType is None and vdesc["type"]:
self.fd.write("# % type: {}\n".format(vdesc["type"]))

if vdesc["value"]:
self.fd.write("# % answer: {}\n".format(vdesc["value"]))
self.fd.write("# %end\n")

# import modules
self.fd.write(
r"""
Expand Down Expand Up @@ -3489,8 +3519,11 @@ def cleanup():
self.fd.write(" pass\n")

self.fd.write("\ndef main(options, flags):\n")
modelVars = self.model.GetVariables()
for item in self.model.GetItems(ModelAction):
self._writeItem(item, variables=item.GetParameterizedParams())
modelParams = item.GetParameterizedParams()
modelParams["vars"] = modelVars
self._writeItem(item, variables=modelParams)

self.fd.write(" return 0\n")

Expand Down Expand Up @@ -3533,6 +3566,45 @@ def _writePythonAction(self, item, variables={}, intermediates=None):
strcmd + self._getPythonActionCmd(item, task, len(strcmd), variables) + "\n"
)

def _substitutePythonParamValue(
self, value, name, parameterizedParams, variables, item
):
"""Substitute parameterized options or variables.

:param value: parameter value to be substituted
:param name: parameter name
:param parameterizedParams: list of parameterized options
:param variables: list of user-defined variables
:param item: item object

:return: substituted value
"""
foundVar = False
parameterizedValue = value

if name in parameterizedParams:
foundVar = True
parameterizedValue = 'options["{}"]'.format(self._getParamName(name, item))
else:
# check for variables
formattedVar = False
for var in variables["vars"]:
pattern = re.compile("%" + var)
found = pattern.search(value)
if found:
foundVar = True
if found.end() != len(value):
formattedVar = True
parameterizedValue = pattern.sub(
"{options['" + var + "']}", value
)
else:
parameterizedValue = f'options["{var}"]'
if formattedVar:
parameterizedValue = 'f"' + parameterizedValue + '"'

return foundVar, parameterizedValue

def _getPythonActionCmd(self, item, task, cmdIndent, variables={}):
opts = task.get_options()

Expand Down Expand Up @@ -3560,11 +3632,18 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}):
value = list(map(float, value))

if (name and value) or (name in parameterizedParams):
foundVar = False

if name in parameterizedParams:
foundVar = True
value = 'options["{}"]'.format(self._getParamName(name, item))
if isinstance(value, list):
foundVar = False
for idx in range(len(value)):
foundVar_, value[idx] = self._substitutePythonParamValue(
value[idx], name, parameterizedParams, variables, item
)
if foundVar_ is True:
foundVar = True
else:
foundVar, value = self._substitutePythonParamValue(
value, name, parameterizedParams, variables, item
)

if (
foundVar
Expand All @@ -3577,7 +3656,7 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}):

ret += '"%s"' % task.get_name()
if flags:
ret += ",\n{indent}flags='{fl}'".format(indent=" " * cmdIndent, fl=flags)
ret += ',\n{indent}flags="{fl}"'.format(indent=" " * cmdIndent, fl=flags)
if itemParameterizedFlags:
ret += " + getParameterizedFlags(options, [{}])".format(
itemParameterizedFlags
Expand All @@ -3597,40 +3676,6 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}):

return ret

def _substituteVariable(self, string, variable, data):
"""Substitute variable in the string

:param string: string to be modified
:param variable: variable to be substituted
:param data: data related to the variable

:return: modified string
"""
result = ""
ss = re.split(r"\w*(%" + variable + ")w*", string)

if not ss[0] and not ss[-1]:
if data:
return "options['%s']" % variable
else:
return variable

for s in ss:
if not s or s == '"':
continue

if s == "%" + variable:
if data:
result += "+options['%s']+" % variable
else:
result += "+%s+" % variable
else:
result += '"' + s
if not s.endswith("]"): # options
result += '"'

return result.strip("+")


class ModelParamDialog(wx.Dialog):
def __init__(
Expand Down
Loading