[processing] brought back 'export model as python' functionality

This commit is contained in:
volaya 2015-11-06 14:02:11 +01:00
parent b05fb0b5b0
commit 227af8ac8e
5 changed files with 134 additions and 5 deletions

View File

@ -127,6 +127,9 @@ class ParameterBoolean(Parameter):
self.value = bool(value)
return True
def getAsScriptCode(self):
return '##' + self.name + '=boolean ' + str(self.default)
class ParameterCrs(Parameter):
@ -153,6 +156,8 @@ class ParameterCrs(Parameter):
def getValueAsCommandLineParameter(self):
return '"' + unicode(self.value) + '"'
def getAsScriptCode(self):
return '##' + self.name + '=crs ' + str(self.default)
class ParameterDataObject(Parameter):
@ -197,6 +202,8 @@ class ParameterExtent(Parameter):
def getValueAsCommandLineParameter(self):
return '"' + unicode(self.value) + '"'
def getAsScriptCode(self):
return '##' + self.name + '=extent'
class ParameterFile(Parameter):
@ -225,6 +232,12 @@ class ParameterFile(Parameter):
else:
return 'file'
def getAsScriptCode(self):
if self.isFolder:
return '##' + self.name + '=folder'
else:
return '##' + self.name + '=file'
class ParameterFixedTable(Parameter):
@ -406,6 +419,13 @@ class ParameterMultipleInput(ParameterDataObject):
else:
return 'any vectors'
def getAsScriptCode(self):
if self.datatype == self.TYPE_RASTER:
return '##' + self.name + '=multiple raster'
if self.datatype == self.TYPE_FILE:
return '##' + self.name + '=multiple file'
else:
return '##' + self.name + '=multiple vector'
class ParameterNumber(Parameter):
@ -451,6 +471,9 @@ class ParameterNumber(Parameter):
return False
def getAsScriptCode(self):
return '##' + self.name + '=number ' + str(self.default)
class ParameterRange(Parameter):
def __init__(self, name='', description='', default='0,1', optional=False):
@ -543,6 +566,9 @@ class ParameterRaster(ParameterDataObject):
exts[i] = self.tr('%s files(*.%s)', 'ParameterRaster') % (exts[i].upper(), exts[i].lower())
return ';;'.join(exts)
def getAsScriptCode(self):
return '##' + self.name + '=raster'
class ParameterSelection(Parameter):
@ -609,6 +635,8 @@ class ParameterString(Parameter):
ParameterString.ESCAPED_NEWLINE)) + '"'
if self.value is not None else unicode(None))
def getAsScriptCode(self):
return '##' + self.name + '=string ' + self.default
class ParameterTable(ParameterDataObject):
@ -674,6 +702,9 @@ class ParameterTable(ParameterDataObject):
exts[i] = self.tr('%s files(*.%s)', 'ParameterTable') % (exts[i].upper(), exts[i].lower())
return ';;'.join(exts)
def getAsScriptCode(self):
return '##' + self.name + '=table'
class ParameterTableField(Parameter):
@ -715,6 +746,9 @@ class ParameterTableField(Parameter):
else:
return 'any'
def getAsScriptCode(self):
return '##' + self.name + '=field ' + self.parent
class ParameterVector(ParameterDataObject):
@ -800,6 +834,9 @@ class ParameterVector(ParameterDataObject):
return types[:-2]
def getAsScriptCode(self):
return '##' + self.name + '=vector'
class ParameterGeometryPredicate(Parameter):

View File

@ -89,7 +89,7 @@ class Algorithm():
#A dict of Input object. keys are param names
self.params = {}
#A dict of Output with final output descriptions. Keys are output names.
#A dict of ModelerOutput with final output descriptions. Keys are output names.
#Outputs not final are not stored in this dict
self.outputs = {}
@ -119,6 +119,33 @@ class Algorithm():
name = self.consoleName + "_" + unicode(i)
self.name = name
def getOutputType(self, outputName):
output = self.algorithm.getOutputFromName(outputName)
return "output " + output.__class__.__name__.split(".")[-1][6:].lower()
def toPython(self):
s = []
params = []
for param in self.algorithm.parameters:
value = self.params[param.name]
def _toString(v):
if isinstance(v, (ValueFromInput, ValueFromOutput)):
return v.asPythonParameter()
elif isinstance(v, basestring):
return "'%s'" % v
elif isinstance(v, list):
return "[%s]" % ",".join([_toString(val) for val in v])
else:
return unicode(value)
params.append(_toString(value))
for out in self.algorithm.outputs:
if out.name in self.outputs:
params.append(safeName(self.outputs[out.name].description).lower())
else:
params.append(str(None))
s.append("outputs_%s=processing.runalg('%s', %s)" % (self.name, self.consoleName, ",".join(params)))
return s
class ValueFromInput():
@ -137,6 +164,8 @@ class ValueFromInput():
except:
return False
def asPythonParameter(self):
return self.name
class ValueFromOutput():
@ -156,6 +185,9 @@ class ValueFromOutput():
def __str__(self):
return self.alg + "," + self.output
def asPythonParameter(self):
return "outputs_%s['%s']" % (self.alg, self.output)
class ModelerAlgorithm(GeoAlgorithm):
@ -654,3 +686,33 @@ class ModelerAlgorithm(GeoAlgorithm):
raise e
else:
raise WrongModelException(_tr('Error in model definition line: ') + '%s\n%s' % (line.strip(), traceback.format_exc()))
def toPython(self):
s = ['##%s=name' % self.name]
for param in self.inputs.values():
s.append(param.param.getAsScriptCode())
for alg in self.algs.values():
for name, out in alg.outputs.iteritems():
s.append('##%s=%s' % (safeName(out.description).lower(), alg.getOutputType(name)))
executed = []
toExecute = [alg for alg in self.algs.values() if alg.active]
while len(executed) < len(toExecute):
for alg in toExecute:
if alg.name not in executed:
canExecute = True
required = self.getDependsOnAlgorithms(alg.name)
for requiredAlg in required:
if requiredAlg != alg.name and requiredAlg not in executed:
canExecute = False
break
if canExecute:
s.extend(alg.toPython())
executed.append(alg.name)
return '\n'.join(s)
def safeName(name):
validChars = 'abcdefghijklmnopqrstuvwxyz'
return ''.join(c for c in name.lower() if c in validChars)

View File

@ -39,7 +39,6 @@ from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.ProcessingLog import ProcessingLog
from processing.gui.HelpEditionDialog import HelpEditionDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
import processing.gui.AlgorithmClassification
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm, ModelerParameter
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
@ -161,6 +160,7 @@ class ModelerDialog(BASE, WIDGET):
self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
self.btnSaveAs.setIcon(QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
self.btnExportImage.setIcon(QgsApplication.getThemeIcon('/mActionSaveMapAsImage.png'))
self.btnExportPython.setIcon(QgsApplication.getThemeIcon('/console/iconSaveAsConsole.png'))
self.btnEditHelp.setIcon(QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
self.btnRun.setIcon(QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))
@ -184,6 +184,7 @@ class ModelerDialog(BASE, WIDGET):
self.btnSave.clicked.connect(self.save)
self.btnSaveAs.clicked.connect(self.saveAs)
self.btnExportImage.clicked.connect(self.exportAsImage)
self.btnExportPython.clicked.connect(self.exportAsPython)
self.btnEditHelp.clicked.connect(self.editHelp)
self.btnRun.clicked.connect(self.runModel)
@ -281,6 +282,23 @@ class ModelerDialog(BASE, WIDGET):
img.save(filename)
def exportAsPython(self):
filename = unicode(QFileDialog.getSaveFileName(self,
self.tr('Save Model As Python Script'), '',
self.tr('Python files (*.py *.PY)')))
if not filename:
return
if not filename.lower().endswith('.py'):
filename += '.py'
text = self.alg.toPython()
with codecs.open(filename, 'w', encoding='utf-8') as fout:
fout.write(text)
QMessageBox.information(self, self.tr('Model exported'),
self.tr('Model was correctly exported.'))
def saveModel(self, saveAs):
if unicode(self.textGroup.text()).strip() == '' \
or unicode(self.textName.text()).strip() == '':

View File

@ -198,7 +198,7 @@ class ModelerParameterDefinitionDialog(QDialog):
self.yesNoCombo.setCurrentIndex(
1 if self.param.optional else 0)
self.verticalLayout.addLayout(self.horizontalLayout2)
self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setOrientation(Qt.Horizontal)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
@ -221,8 +221,10 @@ class ModelerParameterDefinitionDialog(QDialog):
validChars = \
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
safeName = ''.join(c for c in description if c in validChars)
name = self.paramType.upper().replace(' ', '') + '_' \
+ safeName.upper()
name = safeName.lower()
i = 2
while name in self.alg.inputs:
name = safeName.lower() + str(i)
else:
name = self.param.name
if self.paramType \

View File

@ -96,6 +96,16 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnExportPython">
<property name="text">
<string>...</string>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">