Skip to content

Commit 227af8a

Browse files
committedNov 6, 2015
[processing] brought back 'export model as python' functionality
1 parent b05fb0b commit 227af8a

File tree

5 files changed

+134
-5
lines changed

5 files changed

+134
-5
lines changed
 

‎python/plugins/processing/core/parameters.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ def setValue(self, value):
127127
self.value = bool(value)
128128
return True
129129

130+
def getAsScriptCode(self):
131+
return '##' + self.name + '=boolean ' + str(self.default)
132+
130133

131134
class ParameterCrs(Parameter):
132135

@@ -153,6 +156,8 @@ def setValue(self, value):
153156
def getValueAsCommandLineParameter(self):
154157
return '"' + unicode(self.value) + '"'
155158

159+
def getAsScriptCode(self):
160+
return '##' + self.name + '=crs ' + str(self.default)
156161

157162
class ParameterDataObject(Parameter):
158163

@@ -197,6 +202,8 @@ def setValue(self, text):
197202
def getValueAsCommandLineParameter(self):
198203
return '"' + unicode(self.value) + '"'
199204

205+
def getAsScriptCode(self):
206+
return '##' + self.name + '=extent'
200207

201208
class ParameterFile(Parameter):
202209

@@ -225,6 +232,12 @@ def typeName(self):
225232
else:
226233
return 'file'
227234

235+
def getAsScriptCode(self):
236+
if self.isFolder:
237+
return '##' + self.name + '=folder'
238+
else:
239+
return '##' + self.name + '=file'
240+
228241

229242
class ParameterFixedTable(Parameter):
230243

@@ -406,6 +419,13 @@ def dataType(self):
406419
else:
407420
return 'any vectors'
408421

422+
def getAsScriptCode(self):
423+
if self.datatype == self.TYPE_RASTER:
424+
return '##' + self.name + '=multiple raster'
425+
if self.datatype == self.TYPE_FILE:
426+
return '##' + self.name + '=multiple file'
427+
else:
428+
return '##' + self.name + '=multiple vector'
409429

410430
class ParameterNumber(Parameter):
411431

@@ -451,6 +471,9 @@ def setValue(self, n):
451471
return False
452472

453473

474+
def getAsScriptCode(self):
475+
return '##' + self.name + '=number ' + str(self.default)
476+
454477
class ParameterRange(Parameter):
455478

456479
def __init__(self, name='', description='', default='0,1', optional=False):
@@ -543,6 +566,9 @@ def getFileFilter(self):
543566
exts[i] = self.tr('%s files(*.%s)', 'ParameterRaster') % (exts[i].upper(), exts[i].lower())
544567
return ';;'.join(exts)
545568

569+
def getAsScriptCode(self):
570+
return '##' + self.name + '=raster'
571+
546572

547573
class ParameterSelection(Parameter):
548574

@@ -609,6 +635,8 @@ def getValueAsCommandLineParameter(self):
609635
ParameterString.ESCAPED_NEWLINE)) + '"'
610636
if self.value is not None else unicode(None))
611637

638+
def getAsScriptCode(self):
639+
return '##' + self.name + '=string ' + self.default
612640

613641
class ParameterTable(ParameterDataObject):
614642

@@ -674,6 +702,9 @@ def getFileFilter(self):
674702
exts[i] = self.tr('%s files(*.%s)', 'ParameterTable') % (exts[i].upper(), exts[i].lower())
675703
return ';;'.join(exts)
676704

705+
def getAsScriptCode(self):
706+
return '##' + self.name + '=table'
707+
677708

678709
class ParameterTableField(Parameter):
679710

@@ -715,6 +746,9 @@ def dataType(self):
715746
else:
716747
return 'any'
717748

749+
def getAsScriptCode(self):
750+
return '##' + self.name + '=field ' + self.parent
751+
718752

719753
class ParameterVector(ParameterDataObject):
720754

@@ -800,6 +834,9 @@ def dataType(self):
800834

801835
return types[:-2]
802836

837+
def getAsScriptCode(self):
838+
return '##' + self.name + '=vector'
839+
803840

804841
class ParameterGeometryPredicate(Parameter):
805842

‎python/plugins/processing/modeler/ModelerAlgorithm.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def __init__(self, consoleName=""):
8989
#A dict of Input object. keys are param names
9090
self.params = {}
9191

92-
#A dict of Output with final output descriptions. Keys are output names.
92+
#A dict of ModelerOutput with final output descriptions. Keys are output names.
9393
#Outputs not final are not stored in this dict
9494
self.outputs = {}
9595

@@ -119,6 +119,33 @@ def setName(self, model):
119119
name = self.consoleName + "_" + unicode(i)
120120
self.name = name
121121

122+
def getOutputType(self, outputName):
123+
output = self.algorithm.getOutputFromName(outputName)
124+
return "output " + output.__class__.__name__.split(".")[-1][6:].lower()
125+
126+
def toPython(self):
127+
s = []
128+
params = []
129+
for param in self.algorithm.parameters:
130+
value = self.params[param.name]
131+
def _toString(v):
132+
if isinstance(v, (ValueFromInput, ValueFromOutput)):
133+
return v.asPythonParameter()
134+
elif isinstance(v, basestring):
135+
return "'%s'" % v
136+
elif isinstance(v, list):
137+
return "[%s]" % ",".join([_toString(val) for val in v])
138+
else:
139+
return unicode(value)
140+
params.append(_toString(value))
141+
for out in self.algorithm.outputs:
142+
if out.name in self.outputs:
143+
params.append(safeName(self.outputs[out.name].description).lower())
144+
else:
145+
params.append(str(None))
146+
s.append("outputs_%s=processing.runalg('%s', %s)" % (self.name, self.consoleName, ",".join(params)))
147+
return s
148+
122149

123150
class ValueFromInput():
124151

@@ -137,6 +164,8 @@ def __eq__(self, other):
137164
except:
138165
return False
139166

167+
def asPythonParameter(self):
168+
return self.name
140169

141170
class ValueFromOutput():
142171

@@ -156,6 +185,9 @@ def __eq__(self, other):
156185
def __str__(self):
157186
return self.alg + "," + self.output
158187

188+
def asPythonParameter(self):
189+
return "outputs_%s['%s']" % (self.alg, self.output)
190+
159191

160192
class ModelerAlgorithm(GeoAlgorithm):
161193

@@ -654,3 +686,33 @@ def _tr(s):
654686
raise e
655687
else:
656688
raise WrongModelException(_tr('Error in model definition line: ') + '%s\n%s' % (line.strip(), traceback.format_exc()))
689+
690+
691+
def toPython(self):
692+
s = ['##%s=name' % self.name]
693+
for param in self.inputs.values():
694+
s.append(param.param.getAsScriptCode())
695+
for alg in self.algs.values():
696+
for name, out in alg.outputs.iteritems():
697+
s.append('##%s=%s' % (safeName(out.description).lower(), alg.getOutputType(name)))
698+
699+
executed = []
700+
toExecute = [alg for alg in self.algs.values() if alg.active]
701+
while len(executed) < len(toExecute):
702+
for alg in toExecute:
703+
if alg.name not in executed:
704+
canExecute = True
705+
required = self.getDependsOnAlgorithms(alg.name)
706+
for requiredAlg in required:
707+
if requiredAlg != alg.name and requiredAlg not in executed:
708+
canExecute = False
709+
break
710+
if canExecute:
711+
s.extend(alg.toPython())
712+
executed.append(alg.name)
713+
714+
return '\n'.join(s)
715+
716+
def safeName(name):
717+
validChars = 'abcdefghijklmnopqrstuvwxyz'
718+
return ''.join(c for c in name.lower() if c in validChars)

‎python/plugins/processing/modeler/ModelerDialog.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
from processing.core.ProcessingLog import ProcessingLog
4040
from processing.gui.HelpEditionDialog import HelpEditionDialog
4141
from processing.gui.AlgorithmDialog import AlgorithmDialog
42-
import processing.gui.AlgorithmClassification
4342
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
4443
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm, ModelerParameter
4544
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
@@ -161,6 +160,7 @@ def _mimeDataAlgorithm(items):
161160
self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
162161
self.btnSaveAs.setIcon(QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
163162
self.btnExportImage.setIcon(QgsApplication.getThemeIcon('/mActionSaveMapAsImage.png'))
163+
self.btnExportPython.setIcon(QgsApplication.getThemeIcon('/console/iconSaveAsConsole.png'))
164164
self.btnEditHelp.setIcon(QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
165165
self.btnRun.setIcon(QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))
166166

@@ -184,6 +184,7 @@ def _mimeDataAlgorithm(items):
184184
self.btnSave.clicked.connect(self.save)
185185
self.btnSaveAs.clicked.connect(self.saveAs)
186186
self.btnExportImage.clicked.connect(self.exportAsImage)
187+
self.btnExportPython.clicked.connect(self.exportAsPython)
187188
self.btnEditHelp.clicked.connect(self.editHelp)
188189
self.btnRun.clicked.connect(self.runModel)
189190

@@ -281,6 +282,23 @@ def exportAsImage(self):
281282

282283
img.save(filename)
283284

285+
def exportAsPython(self):
286+
filename = unicode(QFileDialog.getSaveFileName(self,
287+
self.tr('Save Model As Python Script'), '',
288+
self.tr('Python files (*.py *.PY)')))
289+
if not filename:
290+
return
291+
292+
if not filename.lower().endswith('.py'):
293+
filename += '.py'
294+
295+
text = self.alg.toPython()
296+
with codecs.open(filename, 'w', encoding='utf-8') as fout:
297+
fout.write(text)
298+
QMessageBox.information(self, self.tr('Model exported'),
299+
self.tr('Model was correctly exported.'))
300+
301+
284302
def saveModel(self, saveAs):
285303
if unicode(self.textGroup.text()).strip() == '' \
286304
or unicode(self.textName.text()).strip() == '':

‎python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def setupUi(self):
198198
self.yesNoCombo.setCurrentIndex(
199199
1 if self.param.optional else 0)
200200
self.verticalLayout.addLayout(self.horizontalLayout2)
201-
201+
202202
self.buttonBox = QDialogButtonBox(self)
203203
self.buttonBox.setOrientation(Qt.Horizontal)
204204
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
@@ -221,8 +221,10 @@ def okPressed(self):
221221
validChars = \
222222
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
223223
safeName = ''.join(c for c in description if c in validChars)
224-
name = self.paramType.upper().replace(' ', '') + '_' \
225-
+ safeName.upper()
224+
name = safeName.lower()
225+
i = 2
226+
while name in self.alg.inputs:
227+
name = safeName.lower() + str(i)
226228
else:
227229
name = self.param.name
228230
if self.paramType \

‎python/plugins/processing/ui/DlgModeler.ui

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@
9696
</property>
9797
</widget>
9898
</item>
99+
<item>
100+
<widget class="QToolButton" name="btnExportPython">
101+
<property name="text">
102+
<string>...</string>
103+
</property>
104+
<property name="autoRaise">
105+
<bool>true</bool>
106+
</property>
107+
</widget>
108+
</item>
99109
<item>
100110
<widget class="Line" name="line_2">
101111
<property name="orientation">

0 commit comments

Comments
 (0)
Failed to load comments.