def from_v1_component_spec( cls, v1_component_spec: v1_structures.ComponentSpec) -> 'ComponentSpec': """Converts V1 ComponentSpec to V2 ComponentSpec. Args: v1_component_spec: The V1 ComponentSpec. Returns: Component spec in the form of V2 ComponentSpec. Raises: ValueError: If implementation is not found. TypeError: if any argument is neither a str nor Dict. """ component_dict = v1_component_spec.to_dict() if component_dict.get('implementation') is None: raise ValueError('Implementation field not found') if 'container' not in component_dict.get('implementation'): raise NotImplementedError def _transform_arg( arg: Union[str, Dict[str, str]]) -> ValidCommandArgs: if isinstance(arg, str): return arg if 'inputValue' in arg: return InputValuePlaceholder( input_name=utils.sanitize_input_name(arg['inputValue'])) if 'inputPath' in arg: return InputPathPlaceholder( input_name=utils.sanitize_input_name(arg['inputPath'])) if 'inputUri' in arg: return InputUriPlaceholder( input_name=utils.sanitize_input_name(arg['inputUri'])) if 'outputPath' in arg: return OutputPathPlaceholder( output_name=utils.sanitize_input_name(arg['outputPath'])) if 'outputUri' in arg: return OutputUriPlaceholder( output_name=utils.sanitize_input_name(arg['outputUri'])) if 'if' in arg: if_placeholder_values = arg['if'] if_placeholder_values_then = list( if_placeholder_values['then']) try: if_placeholder_values_else = list( if_placeholder_values['else']) except KeyError: if_placeholder_values_else = [] IfPresentPlaceholderStructure.update_forward_refs() return IfPresentPlaceholder( if_structure=IfPresentPlaceholderStructure( input_name=utils.sanitize_input_name( if_placeholder_values['cond']['isPresent']), then=list( _transform_arg(val) for val in if_placeholder_values_then), otherwise=list( _transform_arg(val) for val in if_placeholder_values_else))) if 'concat' in arg: ConcatPlaceholder.update_forward_refs() return ConcatPlaceholder(concat=list( _transform_arg(val) for val in arg['concat'])) raise ValueError( f'Unexpected command/argument type: "{arg}" of type "{type(arg)}".' ) implementation = component_dict['implementation']['container'] implementation['commands'] = [ _transform_arg(command) for command in implementation.pop('command', []) ] implementation['arguments'] = [ _transform_arg(command) for command in implementation.pop('args', []) ] implementation['env'] = { key: _transform_arg(command) for key, command in implementation.pop('env', {}).items() } container_spec = ContainerSpec(image=implementation['image']) # Workaround for https://github.com/samuelcolvin/pydantic/issues/2079 def _copy_model(obj): if isinstance(obj, BaseModel): return obj.copy(deep=True) return obj # Must assign these after the constructor call, otherwise it won't work. if implementation['commands']: container_spec.commands = [ _copy_model(cmd) for cmd in implementation['commands'] ] if implementation['arguments']: container_spec.arguments = [ _copy_model(arg) for arg in implementation['arguments'] ] if implementation['env']: container_spec.env = { k: _copy_model(v) for k, v in implementation['env'] } return ComponentSpec( name=component_dict.get('name', 'name'), description=component_dict.get('description'), implementation=Implementation(container=container_spec), inputs={ utils.sanitize_input_name(spec['name']): InputSpec(type=spec.get('type', 'Artifact'), default=spec.get('default', None)) for spec in component_dict.get('inputs', []) }, outputs={ utils.sanitize_input_name(spec['name']): OutputSpec(type=spec.get('type', 'Artifact')) for spec in component_dict.get('outputs', []) })
def test_to_dict(self): component_meta = ComponentSpec( name='foobar', description='foobar example', inputs=[ InputSpec(name='input1', description='input1 desc', type={ 'GCSPath': { 'bucket_type': 'directory', 'file_type': 'csv' } }, default='default1'), InputSpec(name='input2', description='input2 desc', type={ 'TFModel': { 'input_data': 'tensor', 'version': '1.8.0' } }, default='default2'), InputSpec(name='input3', description='input3 desc', type='Integer', default='default3'), ], outputs=[ OutputSpec( name='output1', description='output1 desc', type={'Schema': { 'file_type': 'tsv' }}, ) ]) golden_meta = { 'name': 'foobar', 'description': 'foobar example', 'inputs': [{ 'name': 'input1', 'description': 'input1 desc', 'type': { 'GCSPath': { 'bucket_type': 'directory', 'file_type': 'csv' } }, 'default': 'default1' }, { 'name': 'input2', 'description': 'input2 desc', 'type': { 'TFModel': { 'input_data': 'tensor', 'version': '1.8.0' } }, 'default': 'default2' }, { 'name': 'input3', 'description': 'input3 desc', 'type': 'Integer', 'default': 'default3' }], 'outputs': [{ 'name': 'output1', 'description': 'output1 desc', 'type': { 'Schema': { 'file_type': 'tsv' } }, }] } self.assertEqual(component_meta.to_dict(), golden_meta)