chore(sdk): Support loading v1 yaml with {executorInput: } placeholder (#7870)

* Support {executorInput: } placeholder

* merge

* use single quotes for consistency
This commit is contained in:
Chen Sun 2022-06-14 13:14:31 -07:00 committed by GitHub
parent e3fc7cd365
commit f84b51e72d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 10 deletions

View File

@ -21,6 +21,7 @@ import warnings
from typing import Callable, List, Optional, Tuple
import docstring_parser
from kfp.components import placeholders
from kfp.components import python_component
from kfp.components import structures
from kfp.components.types import artifact_types
@ -310,9 +311,6 @@ def extract_component_interface(func: Callable) -> structures.ComponentSpec:
return component_spec
EXECUTOR_INPUT_PLACEHOLDER = "{{$}}"
def _get_command_and_args_for_lightweight_component(
func: Callable) -> Tuple[List[str], List[str]]:
imports_source = [
@ -344,7 +342,7 @@ def _get_command_and_args_for_lightweight_component(
args = [
'--executor_input',
EXECUTOR_INPUT_PLACEHOLDER,
placeholders.ExecutorInputPlaceholder().to_placeholder_string(),
'--function_to_execute',
func.__name__,
]
@ -362,7 +360,7 @@ def _get_command_and_args_for_containerized_component(
args = [
'--executor_input',
EXECUTOR_INPUT_PLACEHOLDER,
placeholders.ExecutorInputPlaceholder().to_placeholder_string(),
'--function_to_execute',
function_name,
]

View File

@ -146,6 +146,16 @@ class RegexPlaceholderSerializationMixin(Placeholder):
return self._TO_PLACEHOLDER.format(**self.to_dict())
class ExecutorInputPlaceholder(base_model.BaseModel,
RegexPlaceholderSerializationMixin):
"""Class that represents executor input placeholder."""
_TO_PLACEHOLDER = '{{$}}'
_FROM_PLACEHOLDER = re.compile(r'\{\{\$\}\}')
def to_placeholder_string(self) -> str:
return self._TO_PLACEHOLDER
class InputValuePlaceholder(base_model.BaseModel,
RegexPlaceholderSerializationMixin):
"""Class that holds an input value placeholder.
@ -236,10 +246,11 @@ class OutputUriPlaceholder(base_model.BaseModel,
)
CommandLineElement = Union[str, InputValuePlaceholder, InputPathPlaceholder,
InputUriPlaceholder, OutputParameterPlaceholder,
OutputPathPlaceholder, OutputUriPlaceholder,
'IfPresentPlaceholder', 'ConcatPlaceholder']
CommandLineElement = Union[str, ExecutorInputPlaceholder, InputValuePlaceholder,
InputPathPlaceholder, InputUriPlaceholder,
OutputParameterPlaceholder, OutputPathPlaceholder,
OutputUriPlaceholder, 'IfPresentPlaceholder',
'ConcatPlaceholder']
class ConcatPlaceholder(base_model.BaseModel, Placeholder):

View File

@ -20,6 +20,21 @@ from kfp.components import placeholders
from kfp.components import structures
class TestExecutorInputPlaceholder(parameterized.TestCase):
@parameterized.parameters([
('{{$}}', placeholders.ExecutorInputPlaceholder()),
])
def test_to_from_placeholder(
self, placeholder_string: str,
placeholder_obj: placeholders.ExecutorInputPlaceholder):
self.assertEqual(
placeholders.ExecutorInputPlaceholder.from_placeholder_string(
placeholder_string), placeholder_obj)
self.assertEqual(placeholder_obj.to_placeholder_string(),
placeholder_string)
class TestInputValuePlaceholder(parameterized.TestCase):
@parameterized.parameters([

View File

@ -412,6 +412,9 @@ def convert_str_or_dict_to_placeholder(
convert_str_or_dict_to_placeholder(e) for e in element['concat']
])
elif first_key == 'executorInput':
return placeholders.ExecutorInputPlaceholder()
else:
raise TypeError(
f'Unexpected command/argument type: "{element}" of type "{type(element)}".'
@ -459,7 +462,8 @@ def _check_valid_placeholder_reference(
for placeholder in placeholder.items:
_check_valid_placeholder_reference(valid_inputs, valid_outputs,
placeholder)
elif not isinstance(placeholder, str):
elif not isinstance(placeholder, placeholders.ExecutorInputPlaceholder
) and not isinstance(placeholder, str):
raise TypeError(
f'Unexpected argument "{placeholder}" of type {type(placeholder)}.')

View File

@ -145,6 +145,43 @@ COMPONENT_SPEC_NESTED_PLACEHOLDER = structures.ComponentSpec(
inputs={'input_prefix': structures.InputSpec(type='String')},
)
V1_YAML_EXECUTOR_INPUT_PLACEHOLDER = textwrap.dedent("""\
name: component_executor_input
inputs:
- {name: input, type: String}
implementation:
container:
image: alpine
command:
- python
- -m
- kfp.containers.entrypoint
args:
- --executor_input
- {executorInput: null}
- --function_name
- test_function
""")
COMPONENT_SPEC_EXECUTOR_INPUT_PLACEHOLDER = structures.ComponentSpec(
name='component_executor_input',
implementation=structures.Implementation(
container=structures.ContainerSpec(
image='alpine',
command=[
'python',
'-m',
'kfp.containers.entrypoint',
],
args=[
'--executor_input',
placeholders.ExecutorInputPlaceholder(),
'--function_name',
'test_function',
])),
inputs={'input': structures.InputSpec(type='String')},
)
class StructuresTest(parameterized.TestCase):
@ -315,6 +352,10 @@ sdkVersion: kfp-2.0.0-alpha.2
'yaml': V1_YAML_NESTED_PLACEHOLDER,
'expected_component': COMPONENT_SPEC_NESTED_PLACEHOLDER
},
{
'yaml': V1_YAML_EXECUTOR_INPUT_PLACEHOLDER,
'expected_component': COMPONENT_SPEC_EXECUTOR_INPUT_PLACEHOLDER
},
)
def test_component_spec_placeholder_load_from_v2_component_yaml(
self, yaml, expected_component):