@@ -409,25 +409,24 @@ def updateStatusFromCache(self):
409409 @property
410410 def statusFile (self ):
411411 if self .range .blockSize == 0 :
412- return os .path .join (self .node .graph . cacheDir , self . node . internalFolder , "status" )
412+ return os .path .join (self .node .internalFolder , "status" )
413413 else :
414- return os .path .join (self .node .graph . cacheDir , self . node . internalFolder ,
414+ return os .path .join (self .node .internalFolder ,
415415 str (self .index ) + ".status" )
416416
417417 @property
418418 def statisticsFile (self ):
419419 if self .range .blockSize == 0 :
420- return os .path .join (self .node .graph . cacheDir , self . node . internalFolder , "statistics" )
420+ return os .path .join (self .node .internalFolder , "statistics" )
421421 else :
422- return os .path .join (self .node .graph .cacheDir , self .node .internalFolder ,
423- str (self .index ) + ".statistics" )
422+ return os .path .join (self .node .internalFolder , str (self .index ) + ".statistics" )
424423
425424 @property
426425 def logFile (self ):
427426 if self .range .blockSize == 0 :
428- return os .path .join (self .node .graph . cacheDir , self . node . internalFolder , "log" )
427+ return os .path .join (self .node .internalFolder , "log" )
429428 else :
430- return os .path .join (self .node .graph . cacheDir , self . node . internalFolder ,
429+ return os .path .join (self .node .internalFolder ,
431430 str (self .index ) + ".log" )
432431
433432 def saveStatusFile (self ):
@@ -674,14 +673,15 @@ def __init__(self, nodeType: str, position: Position = None, parent: BaseObject
674673 self .packageVersion : str = ""
675674 self ._internalFolder : str = ""
676675 self ._sourceCodeFolder : str = ""
676+ self ._internalFolderExp = "{cache}/{nodeType}/{uid}"
677677
678678 # temporary unique name for this node
679679 self ._name : str = f"_{ nodeType } _{ uuid .uuid1 ()} "
680680 self .graph = None
681681 self .dirty : bool = True # whether this node's outputs must be re-evaluated on next Graph update
682682 self ._chunks = ListModel (parent = self )
683683 self ._uid : str = uid
684- self ._cmdVars : dict = {}
684+ self ._expVars : dict = {}
685685 self ._size : int = 0
686686 self ._logManager : Optional [LogManager ] = None
687687 self ._position : Position = position or Position ()
@@ -695,6 +695,11 @@ def __init__(self, nodeType: str, position: Position = None, parent: BaseObject
695695
696696 self .globalStatusChanged .connect (self .updateDuplicatesStatusAndLocked )
697697
698+ self ._staticExpVars = {
699+ "nodeType" : self .nodeType ,
700+ "nodeSourceCodeFolder" : self .sourceCodeFolder
701+ }
702+
698703 def __getattr__ (self , k ):
699704 try :
700705 # Throws exception if not in prototype chain
@@ -913,7 +918,7 @@ def minDepth(self):
913918
914919 @property
915920 def valuesFile (self ):
916- return os .path .join (self .graph . cacheDir , self . internalFolder , 'values' )
921+ return os .path .join (self .internalFolder , 'values' )
917922
918923 def getInputNodes (self , recursive , dependenciesOnly ):
919924 return self .graph .getInputNodes (self , recursive = recursive ,
@@ -954,53 +959,48 @@ def _computeUid(self):
954959 uidAttributes .append (self .nodeType )
955960 self ._uid = hashValue (uidAttributes )
956961
957- def _buildCmdVars (self ):
962+ def _computeInternalFolder (self , cacheDir ):
963+ self ._internalFolder = self ._internalFolderExp .format (
964+ cache = cacheDir or self .graph .cacheDir ,
965+ nodeType = self .nodeType ,
966+ uid = self ._uid )
967+
968+ def _buildExpVars (self ):
958969 """
959970 Generate command variables using input attributes and resolved output attributes
960971 names and values.
961972 """
962- def _buildAttributeCmdVars ( cmdVars , name , attr ):
973+ def _buildAttributeExpVars ( expVars , name , attr ):
963974 if attr .enabled :
964- group = attr .desc .group (attr .node ) \
965- if callable (attr .desc .group ) else attr .desc .group
966- if group is not None :
967- # If there is a valid command line "group"
968- v = attr .getValueStr (withQuotes = True )
969- cmdVars [name ] = f"--{ name } { v } "
970- # xxValue is exposed without quotes to allow to compose expressions
971- cmdVars [name + "Value" ] = attr .getValueStr (withQuotes = False )
975+ # xxValue is exposed without quotes to allow to compose expressions
976+ expVars [name + "Value" ] = attr .getValueStr (withQuotes = False )
972977
973- # List elements may give a fully empty string and will not be sent to the command line.
974- # String attributes will return only quotes if it is empty and thus will be send to the command line.
975- # But a List of string containing 1 element,
976- # and this element is an empty string will also return quotes and will be sent to the command line.
977- if v :
978- cmdVars [group ] = cmdVars .get (group , "" ) + " " + cmdVars [name ]
979- elif isinstance (attr , GroupAttribute ):
978+ if isinstance (attr , GroupAttribute ):
980979 assert isinstance (attr .value , DictModel )
981980 # If the GroupAttribute is not set in a single command line argument,
982981 # the sub-attributes may need to be exposed individually
983982 for v in attr ._value :
984- _buildAttributeCmdVars ( cmdVars , v .name , v )
983+ _buildAttributeExpVars ( expVars , v .name , v )
985984
986- self ._cmdVars ["uid" ] = self ._uid
987- self ._cmdVars ["nodeCacheFolder" ] = self .internalFolder
988- self ._cmdVars ["nodeSourceCodeFolder" ] = self .sourceCodeFolder
985+ self ._expVars = {
986+ "uid" : self ._uid ,
987+ "nodeCacheFolder" : self ._internalFolder ,
988+ }
989989
990990 # Evaluate input params
991991 for name , attr in self ._attributes .objects .items ():
992992 if attr .isOutput :
993993 continue # skip outputs
994- _buildAttributeCmdVars (self ._cmdVars , name , attr )
994+ _buildAttributeExpVars (self ._expVars , name , attr )
995995
996996 # For updating output attributes invalidation values
997- cmdVarsNoCache = self ._cmdVars .copy ()
998- cmdVarsNoCache ["cache" ] = ""
997+ expVarsNoCache = self ._expVars .copy ()
998+ expVarsNoCache ["cache" ] = ""
999999
10001000 # Use "self._internalFolder" instead of "self.internalFolder" because we do not want it to
10011001 # be resolved with the {cache} information ("self.internalFolder" resolves
10021002 # "self._internalFolder")
1003- cmdVarsNoCache ["nodeCacheFolder" ] = self ._internalFolder .format (** cmdVarsNoCache )
1003+ expVarsNoCache ["nodeCacheFolder" ] = self ._internalFolderExp .format (** expVarsNoCache , ** self . _staticExpVars )
10041004
10051005 # Evaluate output params
10061006 for name , attr in self ._attributes .objects .items ():
@@ -1022,8 +1022,8 @@ def _buildAttributeCmdVars(cmdVars, name, attr):
10221022 format (nodeName = self .name , attrName = attr .name ))
10231023 if defaultValue is not None :
10241024 try :
1025- attr .value = defaultValue .format (** self ._cmdVars )
1026- attr ._invalidationValue = defaultValue .format (** cmdVarsNoCache )
1025+ attr .value = defaultValue .format (** self ._expVars )
1026+ attr ._invalidationValue = defaultValue .format (** expVarsNoCache )
10271027 except KeyError as e :
10281028 logging .warning ('Invalid expression with missing key on "{nodeName}.{attrName}" with '
10291029 'value "{defaultValue}".\n Error: {err}' .
@@ -1035,15 +1035,60 @@ def _buildAttributeCmdVars(cmdVars, name, attr):
10351035 format (nodeName = self .name , attrName = attr .name , defaultValue = defaultValue ,
10361036 err = str (e )))
10371037
1038+ # xxValue is exposed without quotes to allow to compose expressions
1039+ self ._expVars [name + 'Value' ] = attr .getValueStr (withQuotes = False )
1040+
1041+
1042+ def createCmdLineVars (self ):
1043+ """
1044+ Generate command variables using input attributes and resolved output attributes
1045+ names and values.
1046+ """
1047+ def _buildAttributeCmdLineVars (cmdLineVars , name , attr ):
1048+ if attr .enabled :
1049+ group = attr .desc .group (attr .node ) \
1050+ if callable (attr .desc .group ) else attr .desc .group
1051+ if group :
1052+ # If there is a valid command line "group"
1053+ v = attr .getValueStr (withQuotes = True )
1054+
1055+ # List elements may give a fully empty string and will not be sent to the command line.
1056+ # String attributes will return only quotes if it is empty and thus will be send to the command line.
1057+ # But a List of string containing 1 element,
1058+ # and this element is an empty string will also return quotes and will be sent to the command line.
1059+ if v :
1060+ cmdLineVars [group ] = cmdLineVars .get (group , "" ) + f" --{ name } { v } "
1061+ elif isinstance (attr , GroupAttribute ):
1062+ assert isinstance (attr .value , DictModel )
1063+ # If the GroupAttribute is not set in a single command line argument,
1064+ # the sub-attributes may need to be exposed individually
1065+ for v in attr ._value :
1066+ _buildAttributeCmdLineVars (cmdLineVars , v .name , v )
1067+
1068+ cmdLineVars = {}
1069+
1070+ # Evaluate input params
1071+ for name , attr in self ._attributes .objects .items ():
1072+ if attr .isOutput :
1073+ continue # skip outputs
1074+ _buildAttributeCmdLineVars (cmdLineVars , name , attr )
1075+
1076+ # Evaluate output params
1077+ for name , attr in self ._attributes .objects .items ():
1078+ if attr .isInput :
1079+ continue # skip inputs
1080+ if not attr .desc .group :
1081+ continue # skip attributes without group
1082+
10381083 v = attr .getValueStr (withQuotes = True )
10391084
1040- self ._cmdVars [name ] = f'--{ name } { v } '
1041- # xxValue is exposed without quotes to allow to compose expressions
1042- self ._cmdVars [name + 'Value' ] = attr .getValueStr (withQuotes = False )
1085+ if not v :
1086+ continue # skip empty strings
10431087
1044- if v :
1045- self ._cmdVars [attr .desc .group ] = \
1046- self ._cmdVars .get (attr .desc .group , '' ) + ' ' + self ._cmdVars [name ]
1088+ cmdLineVars [attr .desc .group ] = \
1089+ cmdLineVars .get (attr .desc .group , '' ) + f' --{ name } { v } '
1090+
1091+ return cmdLineVars
10471092
10481093 @property
10491094 def isParallelized (self ):
@@ -1285,26 +1330,21 @@ def updateInternals(self, cacheDir=None):
12851330 folder = ''
12861331
12871332 # Update command variables / output attributes
1288- self ._cmdVars = {
1289- "cache" : cacheDir or self .graph .cacheDir ,
1290- "nodeType" : self .nodeType ,
1291- "nodeCacheFolder" : self ._internalFolder ,
1292- "nodeSourceCodeFolder" : self .sourceCodeFolder
1293- }
12941333 self ._computeUid ()
1295- self ._buildCmdVars ()
1334+ self ._computeInternalFolder (cacheDir )
1335+ self ._buildExpVars ()
12961336 if self .nodeDesc :
12971337 self .nodeDesc .postUpdate (self )
12981338 # Notify internal folder change if needed
1299- if self .internalFolder != folder :
1339+ if self ._internalFolder != folder :
13001340 self .internalFolderChanged .emit ()
13011341
13021342 def updateInternalAttributes (self ):
13031343 self .internalAttributesChanged .emit ()
13041344
13051345 @property
13061346 def internalFolder (self ):
1307- return self ._internalFolder . format ( ** self . _cmdVars )
1347+ return self ._internalFolder
13081348
13091349 @property
13101350 def sourceCodeFolder (self ):
@@ -1360,7 +1400,7 @@ def prepareLogger(self, iteration=-1):
13601400 if iteration != - 1 :
13611401 chunk = self .chunks [iteration ]
13621402 logFileName = str (chunk .index ) + ".log"
1363- logFile = os .path .join (self .graph . cacheDir , self . internalFolder , logFileName )
1403+ logFile = os .path .join (self .internalFolder , logFileName )
13641404 # Setup logger
13651405 rootLogger = logging .getLogger ()
13661406 self ._logManager = LogManager (rootLogger , logFile )
@@ -1776,7 +1816,6 @@ def __init__(self, nodeType, position=None, parent=None, uid=None, **kwargs):
17761816
17771817 self .packageName = self .nodeDesc .packageName
17781818 self .packageVersion = self .nodeDesc .packageVersion
1779- self ._internalFolder = "{cache}/{nodeType}/{uid}"
17801819 self ._sourceCodeFolder = self .nodeDesc .sourceCodeFolder
17811820
17821821 for attrDesc in self .nodeDesc .inputs :
@@ -1863,7 +1902,6 @@ def toDict(self):
18631902 'split' : self .nbParallelizationBlocks
18641903 },
18651904 'uid' : self ._uid ,
1866- 'internalFolder' : self ._internalFolder ,
18671905 'inputs' : {k : v for k , v in inputs .items () if v is not None }, # filter empty values
18681906 'internalInputs' : {k : v for k , v in internalInputs .items () if v is not None },
18691907 'outputs' : outputs ,
@@ -1926,7 +1964,6 @@ def __init__(self, nodeType, nodeDict, position=None, issue=CompatibilityIssue.U
19261964 self ._inputs = self .nodeDict .get ("inputs" , {})
19271965 self ._internalInputs = self .nodeDict .get ("internalInputs" , {})
19281966 self .outputs = self .nodeDict .get ("outputs" , {})
1929- self ._internalFolder = self .nodeDict .get ("internalFolder" , "" )
19301967 self ._uid = self .nodeDict .get ("uid" , None )
19311968
19321969 # Restore parallelization settings
0 commit comments