@@ -130,34 +130,39 @@ def pipeline_id(self) -> None:
130130
131131 # Input settings
132132 @property
133- def input_settings (self ) -> dict :
133+ def input_settings (self ) -> list [ dict ] | None :
134134 """All parameters needed to run the pipeline
135135 Run show_pipeline() for more information"""
136136 # Return None if the private attribute is unset
137137 return self ._get_input_settings () if self ._is_defined ("_input_settings" ) else None
138138
139139 @input_settings .setter
140- def input_settings (self , input_settings : dict ):
140+ def input_settings (self , input_settings : dict | list [ dict ] ):
141141 # Call deleter if agument is None
142142 if input_settings is None :
143143 del self .input_settings
144144 return
145145 # Display
146146 self ._print ("Input Settings --> " , end = "" , flush = True )
147147 # Check type
148- if not isinstance (input_settings , dict ):
149- raise TypeError ("`input_settings` should be a dictionary" )
150-
148+ is_input_dict_list = isinstance (input_settings , list )
149+ if not isinstance (input_settings , dict ) and not is_input_dict_list :
150+ raise TypeError ("`input_settings` should be a dictionary or a list of dictionnary" )
151+
151152 # Check if each input can be converted to a string with valid characters and no empty strings
152- self ._check_invalid_input (input_settings )
153-
154- # Parse the input settings
155- new_settings = self ._parse_input_settings (input_settings )
156- self ._print ("parsed" )
157- # Check conflicts with private attribute
158- self ._check_value ("_input_settings" , new_settings )
159- # Update
160- self ._input_settings = new_settings
153+ inputs = input_settings if is_input_dict_list else [input_settings ]
154+ new_input_settings = []
155+ for input_dict in inputs :
156+ self ._check_invalid_input (input_dict )
157+ # Parse the input settings
158+ new_settings = self ._parse_input_settings (input_dict )
159+ self ._print ("parsed" )
160+ # Check conflicts with private attribute
161+ self ._check_value ("_input_settings" , new_settings )
162+ # Update
163+ new_input_settings .append (new_settings )
164+
165+ self ._input_settings = new_input_settings
161166
162167 @input_settings .deleter
163168 def input_settings (self ) -> None :
@@ -556,7 +561,7 @@ def monitor_workflows(self, refresh_time=30) -> VipLauncher:
556561 self ._print ("Run launch_pipeline() to launch workflows on VIP." )
557562 return self
558563 # Update existing workflows
559- self ._print ("Updating worflow inventory ... " , end = "" , flush = True )
564+ self ._print ("Updating workflow inventory ... " , end = "" , flush = True )
560565 self ._update_workflows ()
561566 self ._print ("Done." )
562567 # Check if workflows are still running
@@ -565,7 +570,7 @@ def monitor_workflows(self, refresh_time=30) -> VipLauncher:
565570 self ._execution_report ()
566571 # Display standby
567572 self ._print ("\n -------------------------------------------------------------" )
568- self ._print ("The current proccess will wait until all executions are over." )
573+ self ._print ("The current process will wait until all executions are over." )
569574 self ._print ("Their progress can be monitored on VIP portal:" )
570575 self ._print (f"\t { self ._VIP_PORTAL } " )
571576 self ._print ("-------------------------------------------------------------" )
@@ -1538,21 +1543,21 @@ def parse_value(input):
15381543 }
15391544
15401545 # Get the input settings after files are parsed as PathLib objects
1541- def _get_input_settings (self , location = "vip" ) -> dict :
1546+ def _get_input_settings (self , location = "vip" ) -> list [ dict ] :
15421547 """
15431548 Returns the input settings with their orignal values in string format.
15441549 `location` is destined to subclasses.
15451550 """
15461551 if location != "vip" :
15471552 raise NotImplementedError (f"Unknown location: { location } " )
1548- return {
1549- key : [str (v ) for v in value ] if isinstance (value , list ) else str (value )
1550- for key , value in self ._input_settings . items ()
1551- }
1553+ return [
1554+ { key : [str (v ) for v in value ] if isinstance (value , list ) else str (value ) for key , value in input_dict . items ()}
1555+ for input_dict in self ._input_settings
1556+ ]
15521557 # ------------------------------------------------
15531558
15541559 # Check the input settings based on the pipeline descriptor
1555- def _check_input_settings (self , input_settings : dict = None , location : str = None ) -> None :
1560+ def _check_input_settings (self , input_settings : list [ dict ] = None , location : str = None ) -> None :
15561561 """
15571562 Checks `input_settings` with respect to pipeline descriptor. If not provided, checks the instance property.
15581563 Prerequisite: input_settings contains only strings or lists of strings.
@@ -1580,10 +1585,12 @@ def _check_input_settings(self, input_settings: dict=None, location: str=None) -
15801585 # Check the pipeline identifier
15811586 if not self ._is_defined ("_pipeline_id" ):
15821587 raise AttributeError ("Input settings could not be checked without a pipeline identifier." )
1583- # Parameter names
1584- self ._check_input_keys (input_settings )
1585- # Parameter values
1586- self ._check_input_values (input_settings , location = location )
1588+
1589+ for input_dict in input_settings :
1590+ # Parameter names
1591+ self ._check_input_keys (input_dict )
1592+ # Parameter values
1593+ self ._check_input_values (input_dict , location = location )
15871594 # Return True when all checks are complete
15881595 return True
15891596 # ------------------------------------------------
@@ -1677,7 +1684,9 @@ def _check_input_values(self, input_settings: dict, location: str) -> None:
16771684 missing_files .extend (missing_files_found )
16781685 continue
16791686 if param ["type" ] == "Boolean" :
1680- if value not in ["true" , "false" ]:
1687+ # Handle boolean lists
1688+ values = value if isinstance (value , list ) else [value ]
1689+ if not all (v in ["true" , "false" ] for v in values ):
16811690 wrong_type_inputs .append (name )
16821691 continue
16831692 # Check other input formats ?
0 commit comments