Skip to content

Commit 163218f

Browse files
author
Guillaume V.
committed
New [Inputs] : input_settings are now list of input maps, handles both dicts/lists for user
1 parent 3f8eae3 commit 163218f

3 files changed

Lines changed: 44 additions & 35 deletions

File tree

src/vip_client/classes/VipLauncher.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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 ?

src/vip_client/classes/VipSession.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ def parse_value(input):
11401140
# ------------------------------------------------
11411141

11421142
# Get the input settings after they are parsed
1143-
def _get_input_settings(self, location="vip") -> dict:
1143+
def _get_input_settings(self, location="vip") -> list[dict]:
11441144
"""
11451145
Fits `self._input_settings` to `location`, i.e. write the input paths relatively to `location`.
11461146
Returns the modified settings.
@@ -1173,10 +1173,10 @@ def get_input(value, location) -> str:
11731173
if location not in ("vip", "local"):
11741174
raise NotImplementedError(f"Unknown location: {location}")
11751175
# Browse input settings
1176-
return {
1177-
key: get_input(value, location)
1178-
for key, value in self._input_settings.items()
1179-
}
1176+
return [
1177+
{key: get_input(value, location) for key, value in input_dict.items()}
1178+
for input_dict in self._input_settings
1179+
]
11801180
# ------------------------------------------------
11811181

11821182
def _update_input_settings(self) -> None:
@@ -1185,7 +1185,7 @@ def _update_input_settings(self) -> None:
11851185
This method does nothing if `input_settings` is unset.
11861186
"""
11871187
if self._is_defined('_input_settings'):
1188-
self._input_settings = self._parse_input_settings(self._input_settings)
1188+
self._input_settings = [self._parse_input_settings(input_dict) for input_dict in self._input_settings]
11891189
# ------------------------------------------------
11901190

11911191
# Function to convert a VIP path to local output directory

src/vip_client/utils/vip.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ def count_executions()->int:
350350
return int(rq.text)
351351

352352
# -----------------------------------------------------------------------------
353-
def init_exec(pipeline, name="default", inputValues={}, resultsLocation="/vip/Home") -> str:
353+
def init_exec(pipeline, name="default", inputValues=[], resultsLocation="/vip/Home") -> str:
354354
url = __PREFIX + 'executions'
355355
headers = {
356356
'apikey': __apikey,
@@ -359,7 +359,7 @@ def init_exec(pipeline, name="default", inputValues={}, resultsLocation="/vip/Ho
359359
data_ = {
360360
"name": name,
361361
'pipelineIdentifier': pipeline,
362-
"inputValues": inputValues,
362+
"inputValues": [inputValues] if isinstance(inputValues, dict) else inputValues,
363363
"resultsLocation": resultsLocation
364364
}
365365
rq = SESSION.post(url, headers=headers, json=data_)

0 commit comments

Comments
 (0)