2012-10-04 19:33:47 +02:00
# -*- coding: utf-8 -*-
"""
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ModelerAlgorithm . py
- - - - - - - - - - - - - - - - - - - - -
Date : August 2012
Copyright : ( C ) 2012 by Victor Olaya
Email : volayaf at gmail dot com
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
"""
2016-09-21 18:24:26 +02:00
from builtins import str
from builtins import object
2013-10-24 15:26:39 +02:00
2012-10-04 19:33:47 +02:00
__author__ = ' Victor Olaya '
__date__ = ' August 2012 '
__copyright__ = ' (C) 2012, Victor Olaya '
2013-10-01 20:52:22 +03:00
2012-10-04 19:33:47 +02:00
# This will get replaced with a git SHA1 when you do a git archive
2013-10-01 20:52:22 +03:00
2012-10-04 19:33:47 +02:00
__revision__ = ' $Format: % H$ '
2012-12-20 00:16:05 +01:00
import os . path
2014-06-08 00:21:12 +02:00
import sys
import copy
2012-12-20 00:16:05 +01:00
import time
2014-06-08 00:21:12 +02:00
import json
2014-08-22 11:27:57 +02:00
import codecs
import traceback
2016-04-22 10:38:48 +02:00
from qgis . PyQt . QtCore import QCoreApplication , QPointF
from qgis . PyQt . QtGui import QIcon
2016-04-28 18:27:45 +02:00
from operator import attrgetter
2017-01-09 12:34:46 +10:00
from qgis . core import QgsApplication
2015-03-25 17:46:30 +01:00
from qgis . gui import QgsMessageBar
from qgis . utils import iface
2013-08-12 20:44:27 +02:00
from processing . core . GeoAlgorithm import GeoAlgorithm
2014-06-08 00:21:12 +02:00
from processing . modeler . WrongModelException import WrongModelException
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
from processing . core . GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
2016-02-23 14:38:54 +02:00
from processing . core . parameters import ( getParameterFromString ,
ParameterRaster ,
ParameterVector ,
ParameterTable ,
ParameterTableField ,
ParameterBoolean ,
ParameterString ,
ParameterNumber ,
ParameterExtent ,
2016-08-05 10:24:45 +03:00
ParameterCrs ,
2016-02-23 14:38:54 +02:00
ParameterDataObject ,
2016-03-15 16:43:52 +01:00
ParameterMultipleInput )
2016-09-12 06:17:23 +02:00
2014-09-23 10:13:21 +02:00
from processing . gui . Help2Html import getHtmlFromDescriptionsDict
2016-05-19 12:25:04 +02:00
from processing . core . alglist import algList
2012-09-15 18:25:25 +03:00
2015-05-18 19:51:26 +03:00
pluginPath = os . path . split ( os . path . dirname ( __file__ ) ) [ 0 ]
2016-09-21 18:24:26 +02:00
class ModelerParameter ( object ) :
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def __init__ ( self , param = None , pos = None ) :
self . param = param
self . pos = pos
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def todict ( self ) :
return self . __dict__
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
@staticmethod
2014-07-02 07:46:03 +02:00
def fromdict ( d ) :
2014-08-14 10:56:08 +02:00
return ModelerParameter ( d [ " param " ] , d [ " pos " ] )
2014-07-02 07:46:03 +02:00
2016-09-21 18:24:26 +02:00
class ModelerOutput ( object ) :
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def __init__ ( self , description = " " ) :
self . description = description
self . pos = None
def todict ( self ) :
2014-07-02 07:46:03 +02:00
return self . __dict__
2016-09-21 18:24:26 +02:00
class Algorithm ( object ) :
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def __init__ ( self , consoleName = " " ) :
2014-07-02 07:46:03 +02:00
self . name = None
2014-06-08 00:21:12 +02:00
self . description = " "
2014-07-02 07:46:03 +02:00
2016-04-28 18:27:45 +02:00
# The type of the algorithm, indicated as a string, which corresponds
# to the string used to refer to it in the python console
2014-06-08 00:21:12 +02:00
self . consoleName = consoleName
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
self . _algInstance = None
2014-07-02 07:46:03 +02:00
2016-04-28 18:27:45 +02:00
# A dict of Input object. keys are param names
2014-07-02 07:46:03 +02:00
self . params = { }
2016-04-28 18:27:45 +02:00
# A dict of ModelerOutput with final output descriptions. Keys are output names.
# Outputs not final are not stored in this dict
2014-07-02 07:46:03 +02:00
self . outputs = { }
2014-06-08 00:21:12 +02:00
self . pos = None
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
self . dependencies = [ ]
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
self . paramsFolded = True
self . outputsFolded = True
self . active = True
2014-07-02 07:46:03 +02:00
def todict ( self ) :
2016-09-27 19:51:06 +02:00
return { k : v for k , v in list ( self . __dict__ . items ( ) ) if not k . startswith ( " _ " ) }
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
@property
def algorithm ( self ) :
if self . _algInstance is None :
2016-05-19 12:25:04 +02:00
self . _algInstance = algList . getAlgorithm ( self . consoleName ) . getCopy ( )
2014-06-08 00:21:12 +02:00
return self . _algInstance
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def setName ( self , model ) :
if self . name is None :
i = 1
2016-09-21 18:24:26 +02:00
name = self . consoleName + " _ " + str ( i )
2014-06-08 00:21:12 +02:00
while name in model . algs :
i + = 1
2016-09-21 18:24:26 +02:00
name = self . consoleName + " _ " + str ( i )
2014-06-08 00:21:12 +02:00
self . name = name
2014-07-02 07:46:03 +02:00
2015-11-06 14:02:11 +01:00
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 ]
2015-11-10 20:21:10 +00:00
2015-11-06 14:02:11 +01:00
def _toString ( v ) :
if isinstance ( v , ( ValueFromInput , ValueFromOutput ) ) :
return v . asPythonParameter ( )
2016-09-21 18:24:26 +02:00
elif isinstance ( v , str ) :
2015-12-15 14:56:55 +01:00
return " \\ n " . join ( ( " ' %s ' " % v ) . splitlines ( ) )
2015-11-06 14:02:11 +01:00
elif isinstance ( v , list ) :
return " [ %s ] " % " , " . join ( [ _toString ( val ) for val in v ] )
else :
2016-09-21 18:24:26 +02:00
return str ( value )
2015-11-06 14:02:11 +01:00
params . append ( _toString ( value ) )
for out in self . algorithm . outputs :
2016-09-21 10:49:36 +02:00
if not out . hidden :
if out . name in self . outputs :
params . append ( safeName ( self . outputs [ out . name ] . description ) . lower ( ) )
else :
params . append ( str ( None ) )
2015-11-06 14:02:11 +01:00
s . append ( " outputs_ %s =processing.runalg( ' %s ' , %s ) " % ( self . name , self . consoleName , " , " . join ( params ) ) )
return s
2014-10-03 14:44:01 +03:00
2016-09-21 18:24:26 +02:00
class ValueFromInput ( object ) :
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def __init__ ( self , name = " " ) :
self . name = name
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def todict ( self ) :
2014-07-02 07:46:03 +02:00
return self . __dict__
2014-06-08 00:21:12 +02:00
def __str__ ( self ) :
2014-07-02 07:46:03 +02:00
return self . name
2014-06-08 00:21:12 +02:00
def __eq__ ( self , other ) :
try :
return self . name == other . name
except :
2014-07-02 07:46:03 +02:00
return False
2015-11-06 14:02:11 +01:00
def asPythonParameter ( self ) :
return self . name
2014-10-03 14:44:01 +03:00
2015-11-10 20:21:10 +00:00
2016-09-21 18:24:26 +02:00
class ValueFromOutput ( object ) :
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def __init__ ( self , alg = " " , output = " " ) :
self . alg = alg
self . output = output
def todict ( self ) :
return self . __dict__
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def __eq__ ( self , other ) :
try :
return self . alg == other . alg and self . output == other . output
except :
2014-07-02 07:46:03 +02:00
return False
2014-06-08 00:21:12 +02:00
def __str__ ( self ) :
2016-11-17 12:06:54 +01:00
return self . alg + " : " + self . output
2014-07-02 07:46:03 +02:00
2015-11-06 14:02:11 +01:00
def asPythonParameter ( self ) :
return " outputs_ %s [ ' %s ' ] " % ( self . alg , self . output )
2016-09-19 11:52:31 +03:00
2016-09-27 19:51:06 +02:00
class CompoundValue ( object ) :
2016-09-12 06:17:23 +02:00
2016-09-19 11:52:31 +03:00
def __init__ ( self , values = [ ] , definition = " " ) :
2016-09-12 06:17:23 +02:00
self . values = values
self . definition = definition
def todict ( self ) :
return self . __dict__
def __eq__ ( self , other ) :
try :
return self . values == other . values and self . definition == other . definition
except :
return False
def __str__ ( self ) :
return self . definition
def asPythonParameter ( self ) :
2016-09-19 11:52:31 +03:00
return " " # TODO
2016-09-12 06:17:23 +02:00
2014-10-03 14:44:01 +03:00
2012-09-15 18:25:25 +03:00
class ModelerAlgorithm ( GeoAlgorithm ) :
CANVAS_SIZE = 4000
def getCopy ( self ) :
newone = ModelerAlgorithm ( )
newone . provider = self . provider
2016-09-21 08:12:21 +02:00
newone . algs = { }
2016-10-21 10:11:06 +07:00
for algname , alg in self . algs . items ( ) :
2016-09-21 08:12:21 +02:00
newone . algs [ algname ] = Algorithm ( )
newone . algs [ algname ] . __dict__ . update ( copy . deepcopy ( alg . todict ( ) ) )
2014-06-08 00:21:12 +02:00
newone . inputs = copy . deepcopy ( self . inputs )
newone . defineCharacteristics ( )
newone . name = self . name
newone . group = self . group
newone . descriptionFile = self . descriptionFile
2014-11-23 14:03:32 +01:00
newone . helpContent = copy . deepcopy ( self . helpContent )
2012-09-15 18:25:25 +03:00
return newone
def __init__ ( self ) :
2014-10-03 21:56:24 +03:00
self . name = self . tr ( ' Model ' , ' ModelerAlgorithm ' )
2013-10-01 20:52:22 +03:00
# The dialog where this model is being edited
2012-09-15 18:25:25 +03:00
self . modelerdialog = None
self . descriptionFile = None
2014-06-08 00:21:12 +02:00
self . helpContent = { }
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
# Geoalgorithms in this model. A dict of Algorithm objects, with names as keys
self . algs = { }
2014-07-02 07:46:03 +02:00
2016-04-28 18:27:45 +02:00
# Input parameters. A dict of Input objects, with names as keys
2014-06-08 00:21:12 +02:00
self . inputs = { }
GeoAlgorithm . __init__ ( self )
2012-09-15 18:25:25 +03:00
def getIcon ( self ) :
2017-01-09 12:34:46 +10:00
return QgsApplication . getThemeIcon ( " /processingModel.svg " )
2012-09-15 18:25:25 +03:00
2014-07-02 07:46:03 +02:00
def defineCharacteristics ( self ) :
2014-11-21 07:20:48 +01:00
classes = [ ParameterRaster , ParameterVector , ParameterTable , ParameterTableField ,
ParameterBoolean , ParameterString , ParameterNumber ]
self . parameters = [ ]
for c in classes :
2016-09-21 18:24:26 +02:00
for inp in list ( self . inputs . values ( ) ) :
2014-11-21 07:20:48 +01:00
if isinstance ( inp . param , c ) :
self . parameters . append ( inp . param )
2016-09-21 18:24:26 +02:00
for inp in list ( self . inputs . values ( ) ) :
2014-11-21 07:20:48 +01:00
if inp . param not in self . parameters :
self . parameters . append ( inp . param )
2016-10-31 10:53:13 +07:00
self . parameters . sort ( key = attrgetter ( " description " ) )
2014-06-08 00:21:12 +02:00
self . outputs = [ ]
2016-09-21 18:24:26 +02:00
for alg in list ( self . algs . values ( ) ) :
2014-06-08 00:21:12 +02:00
if alg . active :
for out in alg . outputs :
modelOutput = copy . deepcopy ( alg . algorithm . getOutputFromName ( out ) )
modelOutput . name = self . getSafeNameForOutput ( alg . name , out )
modelOutput . description = alg . outputs [ out ] . description
self . outputs . append ( modelOutput )
2015-09-30 08:39:39 +02:00
self . outputs . sort ( key = attrgetter ( " description " ) )
2014-07-02 07:46:03 +02:00
2012-09-15 18:25:25 +03:00
def addParameter ( self , param ) :
2014-06-08 00:21:12 +02:00
self . inputs [ param . param . name ] = param
def updateParameter ( self , param ) :
self . inputs [ param . name ] . param = param
2014-07-02 07:46:03 +02:00
def addAlgorithm ( self , alg ) :
name = self . getNameForAlgorithm ( alg )
alg . name = name
self . algs [ name ] = alg
2014-06-08 00:21:12 +02:00
def getNameForAlgorithm ( self , alg ) :
i = 1
2016-09-21 18:24:26 +02:00
while alg . consoleName . upper ( ) . replace ( " : " , " " ) + " _ " + str ( i ) in list ( self . algs . keys ( ) ) :
2013-10-01 20:52:22 +03:00
i + = 1
2016-09-21 18:24:26 +02:00
return alg . consoleName . upper ( ) . replace ( " : " , " " ) + " _ " + str ( i )
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def updateAlgorithm ( self , alg ) :
2014-07-02 07:46:03 +02:00
alg . pos = self . algs [ alg . name ] . pos
2015-10-06 16:06:37 +02:00
alg . paramsFolded = self . algs [ alg . name ] . paramsFolded
alg . outputsFolded = self . algs [ alg . name ] . outputsFolded
2014-07-02 07:46:03 +02:00
self . algs [ alg . name ] = alg
2013-08-12 20:44:27 +02:00
from processing . modeler . ModelerGraphicItem import ModelerGraphicItem
2014-07-02 07:46:03 +02:00
for i , out in enumerate ( alg . outputs ) :
alg . outputs [ out ] . pos = ( alg . outputs [ out ] . pos or
2015-08-22 14:29:41 +02:00
alg . pos + QPointF (
ModelerGraphicItem . BOX_WIDTH ,
2015-12-15 16:24:12 +01:00
( i + 1.5 ) * ModelerGraphicItem . BOX_HEIGHT ) )
2012-09-15 18:25:25 +03:00
2014-06-08 00:21:12 +02:00
def removeAlgorithm ( self , name ) :
2013-10-01 20:52:22 +03:00
""" Returns True if the algorithm could be removed, False if
others depend on it and could not be removed .
"""
2014-06-08 00:21:12 +02:00
if self . hasDependencies ( name ) :
2012-09-15 18:25:25 +03:00
return False
2014-06-08 00:21:12 +02:00
del self . algs [ name ]
self . modelerdialog . hasChanged = True
2012-09-15 18:25:25 +03:00
return True
2014-06-08 00:21:12 +02:00
def removeParameter ( self , name ) :
2013-10-01 20:52:22 +03:00
""" Returns True if the parameter could be removed, False if
others depend on it and could not be removed .
"""
2014-06-08 00:21:12 +02:00
if self . hasDependencies ( name ) :
2012-09-15 18:25:25 +03:00
return False
2014-07-02 07:46:03 +02:00
del self . inputs [ name ]
self . modelerdialog . hasChanged = True
2012-09-15 18:25:25 +03:00
return True
2014-06-08 00:21:12 +02:00
def hasDependencies ( self , name ) :
2013-10-01 20:52:22 +03:00
""" This method returns True if some other element depends on
the passed one .
2014-07-02 07:46:03 +02:00
"""
2016-09-21 18:24:26 +02:00
for alg in list ( self . algs . values ( ) ) :
for value in list ( alg . params . values ( ) ) :
2014-06-08 00:21:12 +02:00
if value is None :
2014-07-02 07:46:03 +02:00
continue
if isinstance ( value , list ) :
2014-06-08 00:21:12 +02:00
for v in value :
if isinstance ( v , ValueFromInput ) :
if v . name == name :
2012-09-15 18:25:25 +03:00
return True
2014-06-08 00:21:12 +02:00
elif isinstance ( v , ValueFromOutput ) :
if v . alg == name :
return True
if isinstance ( value , ValueFromInput ) :
if value . name == name :
return True
elif isinstance ( value , ValueFromOutput ) :
if value . alg == name :
2014-07-02 07:46:03 +02:00
return True
2016-11-11 12:21:39 +07:00
if alg . name != name :
for dep in alg . dependencies :
if ( dep == name ) :
return True
2012-09-15 18:25:25 +03:00
return False
2014-06-08 00:21:12 +02:00
def getDependsOnAlgorithms ( self , name ) :
""" This method returns a list with names of algorithms
2013-10-01 20:52:22 +03:00
a given one depends on .
"""
2014-06-08 00:21:12 +02:00
alg = self . algs [ name ]
algs = set ( )
algs . update ( set ( alg . dependencies ) )
2016-09-21 18:24:26 +02:00
for value in list ( alg . params . values ( ) ) :
2014-06-08 00:21:12 +02:00
if value is None :
2013-02-03 10:26:43 +01:00
continue
2016-09-12 06:17:23 +02:00
if isinstance ( value , CompoundValue ) :
for v in value . values :
if isinstance ( v , ValueFromOutput ) :
algs . add ( v . alg )
2016-09-19 11:52:31 +03:00
algs . update ( self . getDependsOnAlgorithms ( v . alg ) )
2014-07-02 07:46:03 +02:00
if isinstance ( value , list ) :
2014-06-08 00:21:12 +02:00
for v in value :
if isinstance ( v , ValueFromOutput ) :
algs . add ( v . alg )
2014-07-02 07:46:03 +02:00
algs . update ( self . getDependsOnAlgorithms ( v . alg ) )
2014-06-08 00:21:12 +02:00
elif isinstance ( value , ValueFromOutput ) :
algs . add ( value . alg )
algs . update ( self . getDependsOnAlgorithms ( value . alg ) )
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
return algs
2012-09-15 18:25:25 +03:00
2014-06-08 00:21:12 +02:00
def getDependentAlgorithms ( self , name ) :
""" This method returns a list with the names of algorithms
depending on a given one . It includes the algorithm itself
2014-07-02 07:46:03 +02:00
"""
2014-06-08 00:21:12 +02:00
algs = set ( )
algs . add ( name )
2016-09-21 18:24:26 +02:00
for alg in list ( self . algs . values ( ) ) :
for value in list ( alg . params . values ( ) ) :
2014-06-08 00:21:12 +02:00
if value is None :
2014-07-02 07:46:03 +02:00
continue
2014-06-08 00:21:12 +02:00
if isinstance ( value , list ) :
2014-07-02 07:46:03 +02:00
for v in value :
2014-06-08 00:21:12 +02:00
if isinstance ( v , ValueFromOutput ) and v . alg == name :
algs . update ( self . getDependentAlgorithms ( alg . name ) )
elif isinstance ( value , ValueFromOutput ) and value . alg == name :
2015-12-15 16:24:12 +01:00
algs . update ( self . getDependentAlgorithms ( alg . name ) )
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
return algs
2012-09-15 18:25:25 +03:00
2014-07-02 07:46:03 +02:00
def setPositions ( self , paramPos , algPos , outputsPos ) :
2016-09-27 19:51:06 +02:00
for param , pos in list ( paramPos . items ( ) ) :
2014-06-08 00:21:12 +02:00
self . inputs [ param ] . pos = pos
2016-09-27 19:51:06 +02:00
for alg , pos in list ( algPos . items ( ) ) :
2014-06-08 00:21:12 +02:00
self . algs [ alg ] . pos = pos
2016-09-27 19:51:06 +02:00
for alg , positions in list ( outputsPos . items ( ) ) :
for output , pos in list ( positions . items ( ) ) :
2014-06-08 00:21:12 +02:00
self . algs [ alg ] . outputs [ output ] . pos = pos
def prepareAlgorithm ( self , alg ) :
algInstance = alg . algorithm
for param in algInstance . parameters :
2014-05-21 16:33:20 +02:00
if not param . hidden :
2015-03-25 17:46:30 +01:00
if param . name in alg . params :
2016-09-12 06:17:23 +02:00
value = self . resolveValue ( alg . params [ param . name ] , param )
2015-03-25 17:46:30 +01:00
else :
2016-04-20 14:52:46 +02:00
if iface is not None :
iface . messageBar ( ) . pushMessage ( self . tr ( " Warning " ) ,
self . tr ( " Parameter %s in algorithm %s in the model is run with default value! Edit the model to make sure that this is correct. " ) % ( param . name , alg . name ) ,
QgsMessageBar . WARNING , 4 )
2016-04-27 10:10:18 +02:00
value = param . default
2014-05-21 17:31:12 +02:00
# We allow unexistent filepaths, since that allows
# algorithms to skip some conversion routines
if not param . setValue ( value ) and not isinstance ( param ,
2015-08-22 14:29:41 +02:00
ParameterDataObject ) :
2014-10-03 21:56:24 +03:00
raise GeoAlgorithmExecutionException (
2016-02-17 19:44:05 +01:00
self . tr ( ' Wrong value %s for %s %s ' , ' ModelerAlgorithm ' )
% ( value , param . __class__ . __name__ , param . name ) )
2014-06-08 00:21:12 +02:00
for out in algInstance . outputs :
2014-07-02 07:46:03 +02:00
if not out . hidden :
2014-06-08 00:21:12 +02:00
if out . name in alg . outputs :
name = self . getSafeNameForOutput ( alg . name , out . name )
modelOut = self . getOutputFromName ( name )
if modelOut :
out . value = modelOut . value
2014-05-21 16:33:20 +02:00
else :
out . value = None
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
return algInstance
2014-07-02 07:46:03 +02:00
def deactivateAlgorithm ( self , algName ) :
2014-06-08 00:21:12 +02:00
dependent = self . getDependentAlgorithms ( algName )
for alg in dependent :
self . algs [ alg ] . active = False
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def activateAlgorithm ( self , algName ) :
parents = self . getDependsOnAlgorithms ( algName )
for alg in parents :
if not self . algs [ alg ] . active :
return False
self . algs [ algName ] . active = True
return True
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def getSafeNameForOutput ( self , algName , outName ) :
return outName + ' _ALG ' + algName
2014-07-02 07:46:03 +02:00
2016-09-12 06:17:23 +02:00
def resolveValue ( self , value , param ) :
2014-06-08 00:21:12 +02:00
if value is None :
2016-09-12 06:17:23 +02:00
v = None
2014-06-08 00:21:12 +02:00
if isinstance ( value , list ) :
2016-09-12 06:17:23 +02:00
v = " ; " . join ( [ self . resolveValue ( v , param ) for v in value ] )
elif isinstance ( value , CompoundValue ) :
v = self . resolveValue ( value . definition , param )
elif isinstance ( value , ValueFromInput ) :
v = self . getParameterFromName ( value . name ) . value
2014-06-08 00:21:12 +02:00
elif isinstance ( value , ValueFromOutput ) :
2016-09-12 06:17:23 +02:00
v = self . algs [ value . alg ] . algorithm . getOutputFromName ( value . output ) . value
2014-06-08 00:21:12 +02:00
else :
2016-09-12 06:17:23 +02:00
v = value
return param . evaluateForModeler ( v , self )
2014-07-02 07:46:03 +02:00
2017-01-06 20:04:00 +10:00
def processAlgorithm ( self , feedback ) :
2012-09-15 18:25:25 +03:00
executed = [ ]
2016-09-21 18:24:26 +02:00
toExecute = [ alg for alg in list ( self . algs . values ( ) ) if alg . active ]
2014-07-02 07:46:03 +02:00
while len ( executed ) < len ( toExecute ) :
2014-06-08 00:21:12 +02:00
for alg in toExecute :
if alg . name not in executed :
2012-09-15 18:25:25 +03:00
canExecute = True
2014-06-08 00:21:12 +02:00
required = self . getDependsOnAlgorithms ( alg . name )
2012-09-15 18:25:25 +03:00
for requiredAlg in required :
2014-06-08 00:21:12 +02:00
if requiredAlg != alg . name and requiredAlg not in executed :
2012-09-15 18:25:25 +03:00
canExecute = False
break
if canExecute :
try :
2017-01-06 20:04:00 +10:00
feedback . pushDebugInfo (
2014-10-03 21:56:24 +03:00
self . tr ( ' Prepare algorithm: %s ' , ' ModelerAlgorithm ' ) % alg . name )
2014-06-08 00:21:12 +02:00
self . prepareAlgorithm ( alg )
2017-01-06 20:04:00 +10:00
feedback . setProgressText (
2015-08-22 14:29:41 +02:00
self . tr ( ' Running %s [ %i / %i ] ' , ' ModelerAlgorithm ' ) % ( alg . description , len ( executed ) + 1 , len ( toExecute ) ) )
2017-01-06 20:04:00 +10:00
feedback . pushDebugInfo ( ' Parameters: ' + ' , ' . join ( [ str ( p ) . strip ( )
+ ' = ' + str ( p . value ) for p in alg . algorithm . parameters ] ) )
2012-09-15 18:25:25 +03:00
t0 = time . time ( )
2017-01-06 20:04:00 +10:00
alg . algorithm . execute ( feedback , self )
2014-07-02 07:46:03 +02:00
dt = time . time ( ) - t0
2017-01-04 15:18:17 +07:00
# copy algorithm output value(s) back to model in case the algorithm modified those
for out in alg . algorithm . outputs :
if not out . hidden :
if out . name in alg . outputs :
modelOut = self . getOutputFromName ( self . getSafeNameForOutput ( alg . name , out . name ) )
if modelOut :
modelOut . value = out . value
2014-06-08 00:21:12 +02:00
executed . append ( alg . name )
2017-01-06 20:04:00 +10:00
feedback . pushDebugInfo (
2014-10-03 21:56:24 +03:00
self . tr ( ' OK. Execution took %0.3f ms ( %i outputs). ' , ' ModelerAlgorithm ' ) % ( dt , len ( alg . algorithm . outputs ) ) )
2015-08-22 14:29:41 +02:00
except GeoAlgorithmExecutionException as e :
2017-01-06 20:04:00 +10:00
feedback . pushDebugInfo ( self . tr ( ' Failed ' , ' ModelerAlgorithm ' ) )
2013-10-01 20:52:22 +03:00
raise GeoAlgorithmExecutionException (
2014-10-03 21:56:24 +03:00
self . tr ( ' Error executing algorithm %s \n %s ' , ' ModelerAlgorithm ' ) % ( alg . description , e . msg ) )
2014-07-02 07:46:03 +02:00
2017-01-06 20:04:00 +10:00
feedback . pushDebugInfo (
2014-10-03 21:56:24 +03:00
self . tr ( ' Model processed ok. Executed %i algorithms total ' , ' ModelerAlgorithm ' ) % len ( executed ) )
2014-06-08 00:21:12 +02:00
2012-09-15 18:25:25 +03:00
def getAsCommand ( self ) :
if self . descriptionFile :
return GeoAlgorithm . getAsCommand ( self )
else :
return None
def commandLineName ( self ) :
2014-06-08 00:21:12 +02:00
if self . descriptionFile is None :
return ' '
else :
return ' modeler: ' + os . path . basename ( self . descriptionFile ) [ : - 6 ] . lower ( )
2012-09-15 18:25:25 +03:00
2016-01-19 12:32:25 +01:00
def checkBeforeOpeningParametersDialog ( self ) :
2016-09-21 18:24:26 +02:00
for alg in list ( self . algs . values ( ) ) :
2016-05-19 12:25:04 +02:00
algInstance = algList . getAlgorithm ( alg . consoleName )
2016-01-19 12:32:25 +01:00
if algInstance is None :
return " The model you are trying to run contains an algorithm that is not available: <i> %s </i> " % alg . consoleName
2012-09-15 18:25:25 +03:00
def setModelerView ( self , dialog ) :
self . modelerdialog = dialog
def updateModelerView ( self ) :
if self . modelerdialog :
self . modelerdialog . repaintModel ( )
2014-04-19 00:48:56 +02:00
def help ( self ) :
2014-06-08 00:21:12 +02:00
try :
2014-11-23 14:03:32 +01:00
return True , getHtmlFromDescriptionsDict ( self , self . helpContent )
2014-06-08 00:21:12 +02:00
except :
2014-04-24 17:25:36 +02:00
return False , None
2014-07-02 07:46:03 +02:00
2016-05-28 09:17:21 +02:00
def shortHelp ( self ) :
if ' ALG_DESC ' in self . helpContent :
2016-09-21 18:24:26 +02:00
return self . _formatHelp ( str ( self . helpContent [ ' ALG_DESC ' ] ) )
2016-05-28 09:17:21 +02:00
return None
2016-05-26 11:59:04 +02:00
def getParameterDescriptions ( self ) :
descs = { }
descriptions = self . helpContent
for param in self . parameters :
if param . name in descriptions :
2016-09-21 18:24:26 +02:00
descs [ param . name ] = str ( descriptions [ param . name ] )
2016-05-26 11:59:04 +02:00
return descs
2014-07-02 07:46:03 +02:00
def todict ( self ) :
2014-11-23 14:03:32 +01:00
keys = [ " inputs " , " group " , " name " , " algs " , " helpContent " ]
2016-09-27 19:51:06 +02:00
return { k : v for k , v in list ( self . __dict__ . items ( ) ) if k in keys }
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
def toJson ( self ) :
def todict ( o ) :
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
if isinstance ( o , QPointF ) :
2014-07-02 07:46:03 +02:00
return { " class " : " point " , " values " : { " x " : o . x ( ) , " y " : o . y ( ) } }
2014-06-08 00:21:12 +02:00
try :
d = o . todict ( )
return { " class " : o . __class__ . __module__ + " . " + o . __class__ . __name__ , " values " : d }
2016-03-21 04:58:12 +01:00
except Exception :
2014-06-08 00:21:12 +02:00
pass
2014-07-02 07:46:03 +02:00
return json . dumps ( self , default = todict , indent = 4 )
2014-06-08 00:21:12 +02:00
@staticmethod
def fromJson ( s ) :
2014-07-02 07:46:03 +02:00
def fromdict ( d ) :
2014-06-08 00:21:12 +02:00
try :
fullClassName = d [ " class " ]
2016-12-02 09:35:01 +02:00
if isinstance ( fullClassName , str ) :
tokens = fullClassName . split ( " . " )
else :
tokens = fullClassName . __class__ . __name__ . split ( " . " )
2014-06-08 00:21:12 +02:00
className = tokens [ - 1 ]
moduleName = " . " . join ( tokens [ : - 1 ] )
values = d [ " values " ]
if className == " point " :
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
return QPointF ( values [ " x " ] , values [ " y " ] )
2014-06-08 00:21:12 +02:00
def _import ( name ) :
__import__ ( name )
return sys . modules [ name ]
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2014-07-14 14:19:09 +02:00
if moduleName . startswith ( " processing.parameters " ) :
moduleName = " processing.core.parameters "
2014-06-08 00:21:12 +02:00
module = _import ( moduleName )
clazz = getattr ( module , className )
instance = clazz ( )
2016-09-27 19:51:06 +02:00
for k , v in list ( values . items ( ) ) :
2014-06-08 00:21:12 +02:00
instance . __dict__ [ k ] = v
return instance
except KeyError :
return d
2015-08-22 14:29:41 +02:00
except Exception as e :
2014-07-02 07:46:03 +02:00
raise e
2014-06-08 00:21:12 +02:00
try :
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
model = json . loads ( s , object_hook = fromdict )
2015-08-22 14:29:41 +02:00
except Exception as e :
2014-06-08 00:21:12 +02:00
raise WrongModelException ( e . args [ 0 ] )
return model
2014-07-02 07:46:03 +02:00
2014-06-08 00:21:12 +02:00
@staticmethod
2016-09-12 06:17:23 +02:00
def fromFile ( filename ) :
2014-06-08 00:21:12 +02:00
with open ( filename ) as f :
2014-07-02 07:46:03 +02:00
s = f . read ( )
2014-06-08 00:21:12 +02:00
alg = ModelerAlgorithm . fromJson ( s )
alg . descriptionFile = filename
return alg
2014-07-02 07:46:03 +02:00
2015-11-06 14:02:11 +01:00
def toPython ( self ) :
s = [ ' ## %s =name ' % self . name ]
2016-09-21 18:24:26 +02:00
for param in list ( self . inputs . values ( ) ) :
2015-11-06 14:02:11 +01:00
s . append ( param . param . getAsScriptCode ( ) )
2016-09-21 18:24:26 +02:00
for alg in list ( self . algs . values ( ) ) :
2016-09-27 19:51:06 +02:00
for name , out in list ( alg . outputs . items ( ) ) :
2015-11-06 14:02:11 +01:00
s . append ( ' ## %s = %s ' % ( safeName ( out . description ) . lower ( ) , alg . getOutputType ( name ) ) )
executed = [ ]
2016-09-21 18:24:26 +02:00
toExecute = [ alg for alg in list ( self . algs . values ( ) ) if alg . active ]
2015-11-06 14:02:11 +01:00
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 )
2015-11-10 20:21:10 +00:00
2015-11-06 14:02:11 +01:00
def safeName ( name ) :
validChars = ' abcdefghijklmnopqrstuvwxyz '
2015-11-10 20:21:10 +00:00
return ' ' . join ( c for c in name . lower ( ) if c in validChars )