From 4850cd4460d5d9c55c1292d57c72b183d8d5e563 Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Sat, 11 May 2024 17:43:11 +0200 Subject: [PATCH 1/7] graphical modeler: export variables to Python --- gui/wxpython/gmodeler/model.py | 50 +++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index b33c5b6d4e4..afe2249bf25 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3170,6 +3170,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": @@ -3183,7 +3189,7 @@ def _getStandardizedOption(self, string): elif string == "region": return "G_OPT_M_REGION" - return "" + return None def _writePython(self): """Write model to file""" @@ -3227,7 +3233,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: @@ -3251,7 +3258,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: @@ -3278,6 +3285,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["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""" @@ -3326,8 +3356,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") @@ -3402,6 +3435,15 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): if name in parameterizedParams: foundVar = True value = 'options["{}"]'.format(self._getParamName(name, item)) + else: + # check for variables + for var in variables["vars"]: + pattern = re.compile("%" + var) + if pattern.search(value): + foundVar = True + value = pattern.sub("{options['" + var + "']}", value) + if foundVar: + value = 'f"' + value + '"' if ( foundVar From 834a8cc5cd8dd7cfbf053e65fb575a8d2e0540b1 Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Fri, 31 May 2024 18:04:28 +0200 Subject: [PATCH 2/7] variable description is optional --- gui/wxpython/gmodeler/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index b86ffe6b308..f2ebf983fc1 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3461,7 +3461,7 @@ def _writePython(self): # % required: yes """.format( param_name=vname, - description=vdesc["description"], + description=vdesc.get("description", ""), ) ) if optionType is None and vdesc["type"]: From e2ac8e7556f837d732d498bb8bb9cb4468a155af Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Fri, 31 May 2024 18:25:27 +0200 Subject: [PATCH 3/7] format options only if needed --- gui/wxpython/gmodeler/model.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index f2ebf983fc1..25a6c7d27fa 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3600,12 +3600,18 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): value = 'options["{}"]'.format(self._getParamName(name, item)) else: # check for variables + formattedVar = False for var in variables["vars"]: pattern = re.compile("%" + var) - if pattern.search(value): + found = pattern.search(value) + if found: foundVar = True - value = pattern.sub("{options['" + var + "']}", value) - if foundVar: + if found.end() != len(value): + formattedVar = True + value = pattern.sub("{options['" + var + "']}", value) + else: + value = f"options['{var}']" + if formattedVar: value = 'f"' + value + '"' if ( From e0b559c9b238ca7321f85c161f3d9193fd20a2ab Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Fri, 31 May 2024 18:29:35 +0200 Subject: [PATCH 4/7] switch quotes --- gui/wxpython/gmodeler/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 25a6c7d27fa..ddbc902f771 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3610,7 +3610,7 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): formattedVar = True value = pattern.sub("{options['" + var + "']}", value) else: - value = f"options['{var}']" + value = f'options["{var}"]' if formattedVar: value = 'f"' + value + '"' From 46f1ee90624c86f2b489da899e1fdf56cb17fd93 Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Fri, 31 May 2024 18:31:11 +0200 Subject: [PATCH 5/7] switch quotes for flags too --- gui/wxpython/gmodeler/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index ddbc902f771..2e53414e368 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3625,7 +3625,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 From 8468739d06bc0327b9c28cab07f1da6575e70dac Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Sat, 1 Jun 2024 17:20:57 +0200 Subject: [PATCH 6/7] substitute correctly list of values (pygrass) --- gui/wxpython/gmodeler/model.py | 69 ++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 2e53414e368..b962dd6e5a4 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3566,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() @@ -3593,26 +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)) - else: - # check for variables - formattedVar = False - for var in variables["vars"]: - pattern = re.compile("%" + var) - found = pattern.search(value) - if found: + 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 - if found.end() != len(value): - formattedVar = True - value = pattern.sub("{options['" + var + "']}", value) - else: - value = f'options["{var}"]' - if formattedVar: - value = 'f"' + value + '"' + else: + foundVar, value = self._substitutePythonParamValue( + value, name, parameterizedParams, variables, item + ) if ( foundVar From 25c186debb5a57b6327bf8e383b4011730522ed6 Mon Sep 17 00:00:00 2001 From: Martin Landa Date: Sat, 1 Jun 2024 17:22:12 +0200 Subject: [PATCH 7/7] remove unused method related to substituting variables --- gui/wxpython/gmodeler/model.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index b962dd6e5a4..9d0f58ec7d4 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -3676,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__(