SDK - Python components - Fixed bug when mixing file outputs with return value outputs (#2473)

This commit is contained in:
Alexey Volkov 2019-10-23 19:45:05 -07:00 committed by Kubernetes Prow Robot
parent 7edeca14a1
commit 1282f16335
2 changed files with 65 additions and 3 deletions

View File

@ -463,11 +463,11 @@ def _func_to_component_spec(func, extra_code='', base_image : str = None, packag
line = '_parser.add_argument("{param_flag}", dest="{param_var}", type=str, nargs={nargs})'.format( line = '_parser.add_argument("{param_flag}", dest="{param_var}", type=str, nargs={nargs})'.format(
param_flag=param_flag, param_flag=param_flag,
param_var=output_param_var, param_var=output_param_var,
nargs=len(component_spec.outputs), nargs=len(outputs_passed_through_func_return_tuple),
) )
arg_parse_code_lines.append(line) arg_parse_code_lines.append(line)
arguments.append(param_flag) arguments.append(param_flag)
arguments.extend(OutputPathPlaceholder(output.name) for output in component_spec.outputs) arguments.extend(OutputPathPlaceholder(output.name) for output in outputs_passed_through_func_return_tuple)
output_serialization_expression_strings = [] output_serialization_expression_strings = []
for output in outputs_passed_through_func_return_tuple: for output in outputs_passed_through_func_return_tuple:

View File

@ -17,7 +17,7 @@ import tempfile
import unittest import unittest
from contextlib import contextmanager from contextlib import contextmanager
from pathlib import Path from pathlib import Path
from typing import Callable, Sequence from typing import Callable, NamedTuple, Sequence
import kfp import kfp
import kfp.components as comp import kfp.components as comp
@ -631,6 +631,68 @@ class PythonOpTestCase(unittest.TestCase):
self.helper_test_component_using_local_call(task_factory, arguments={}, expected_output_values={'number': '42'}) self.helper_test_component_using_local_call(task_factory, arguments={}, expected_output_values={'number': '42'})
def test_output_path_plus_return_value(self):
from kfp.components import OutputPath
def write_to_file_path(number_file_path: OutputPath(int)) -> str:
with open(number_file_path, 'w') as f:
f.write(str(42))
return 'Hello'
task_factory = comp.func_to_container_op(write_to_file_path)
self.assertFalse(task_factory.component_spec.inputs)
self.assertEqual(len(task_factory.component_spec.outputs), 2)
self.assertEqual(task_factory.component_spec.outputs[0].type, 'Integer')
self.assertEqual(task_factory.component_spec.outputs[1].type, 'String')
self.helper_test_component_using_local_call(task_factory, arguments={}, expected_output_values={'number': '42', 'output': 'Hello'})
def test_all_data_passing_ways(self):
from kfp.components import InputTextFile, InputPath, OutputTextFile, OutputPath
def write_to_file_path(
file_input1_path: InputPath(str),
file_input2_file: InputTextFile(str),
file_output1_path: OutputPath(str),
file_output2_file: OutputTextFile(str),
value_input1: str = 'foo',
value_input2: str = 'foo',
) -> NamedTuple(
'Outputs', [
('return_output1', str),
('return_output2', str),
]
):
with open(file_input1_path, 'r') as file_input1_file:
with open(file_output1_path, 'w') as file_output1_file:
file_output1_file.write(file_input1_file.read())
file_output2_file.write(file_input2_file.read())
return (value_input1, value_input2)
task_factory = comp.func_to_container_op(write_to_file_path)
self.assertEqual(set(input.name for input in task_factory.component_spec.inputs), {'file_input1', 'file_input2', 'value_input1', 'value_input2'})
self.assertEqual(set(output.name for output in task_factory.component_spec.outputs), {'file_output1', 'file_output2', 'return_output1', 'return_output2'})
self.helper_test_component_using_local_call(
task_factory,
arguments={
'file_input1': 'file_input1_value',
'file_input2': 'file_input2_value',
'value_input1': 'value_input1_value',
'value_input2': 'value_input2_value',
},
expected_output_values={
'file_output1': 'file_input1_value',
'file_output2': 'file_input2_value',
'return_output1': 'value_input1_value',
'return_output2': 'value_input2_value',
},
)
def test_file_input_name_conversion(self): def test_file_input_name_conversion(self):
# Checking the input name conversion rules for file inputs: # Checking the input name conversion rules for file inputs:
# For InputPath, the "_path" suffix is removed # For InputPath, the "_path" suffix is removed