Repository: kubeflow/pipelines

Issue:
[sdk] v2 python component does not support parameter default values
Reproduction: see PR https://github.com/kubeflow/pipelines/pull/5879


Discussion:
/assign @chensun 

Resolving patch:
diff --git a/sdk/python/kfp/dsl/_component_bridge.py b/sdk/python/kfp/dsl/_component_bridge.py
--- a/sdk/python/kfp/dsl/_component_bridge.py
+++ b/sdk/python/kfp/dsl/_component_bridge.py
@@ -202,6 +202,19 @@ def _create_container_op_from_component_and_arguments(
   Returns:
     A ContainerOp instance.
   """
+
+  # Add component inputs with default value to the arguments dict if they are not
+  # in the arguments dict already.
+  arguments = arguments.copy()
+  for input_spec in component_spec.inputs or []:
+    if input_spec.name not in arguments and input_spec.default is not None:
+      default_value = input_spec.default
+      if input_spec.type == 'Integer':
+        default_value = int(default_value)
+      elif input_spec.type == 'Float':
+        default_value = float(default_value)
+      arguments[input_spec.name] = default_value
+
   # Check types of the reference arguments and serialize PipelineParams
   original_arguments = arguments
   arguments = arguments.copy()
@@ -451,7 +464,6 @@ def _resolve_ir_placeholders_v2(
   pipeline_task_spec = pipeline_spec_pb2.PipelineTaskSpec()
 
   # Check types of the reference arguments and serialize PipelineParams
-  original_arguments = arguments
   arguments = arguments.copy()
 
   # Preserve input params for ContainerOp.inputs
@@ -594,7 +606,7 @@ def _resolve_ir_placeholders_v2(
   pipeline_task_spec.task_info.name = (dsl_utils.sanitize_task_name(task.name))
 
   resolved_cmd = _resolve_commands_and_args_v2(
-      component_spec=component_spec, arguments=original_arguments)
+      component_spec=component_spec, arguments=arguments)
 
   task.container_spec = (
       pipeline_spec_pb2.PipelineDeploymentConfig.PipelineContainerSpec(


Test patch:
diff --git a/samples/test/lightweight_python_functions_v2_pipeline.py b/samples/test/lightweight_python_functions_v2_pipeline.py
--- a/samples/test/lightweight_python_functions_v2_pipeline.py
+++ b/samples/test/lightweight_python_functions_v2_pipeline.py
@@ -87,8 +87,6 @@ def train(
     input_list: List[str],
     # An input parameter of type int with a default value.
     num_steps: int = 100,
-    # An input parameter of type string with default value.
-    message_with_default: str = 'hello world',
 ):
   """Dummy Training step"""
   with open(dataset_one_path, 'r') as input_file:
@@ -104,8 +102,6 @@ def train(
           f'input_dict: {input_dict}, type {type(input_dict)} || '
           f'input_list: {input_list}, type {type(input_list)} \n')
   
-  print(f'message_with_default="{message_with_default}"')
-
   with open(model.path, 'w') as output_file:
     for i in range(num_steps):
       output_file.write('Step {}\n{}\n=====\n'.format(i, line))
@@ -125,7 +121,7 @@ def pipeline(message: str = 'message'):
       input_bool=preprocess_task.outputs['output_bool_parameter'],
       input_dict=preprocess_task.outputs['output_dict_parameter'],
       input_list=preprocess_task.outputs['output_list_parameter'],
-      num_steps=5)
+  )
 
 
 if __name__ == '__main__':
diff --git a/samples/test/lightweight_python_functions_v2_pipeline_test.py b/samples/test/lightweight_python_functions_v2_pipeline_test.py
--- a/samples/test/lightweight_python_functions_v2_pipeline_test.py
+++ b/samples/test/lightweight_python_functions_v2_pipeline_test.py
@@ -85,9 +85,7 @@ def verify(
                     'input_dict': '{"A": 1, "B": 2}',
                     'input_list': '["a", "b", "c"]',
                     'message': 'message',
-                    'num_steps': 5,
-                    # TODO: uncomment this, should be "hello world"
-                    # 'message_with_default': "hello world",
+                    'num_steps': 100,
                 }
             },
             'name': 'train',
diff --git a/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.json b/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.json
--- a/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.json
+++ b/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.json
@@ -222,7 +222,7 @@
                 "num_steps": {
                   "runtimeValue": {
                     "constantValue": {
-                      "intValue": "5"
+                      "intValue": "100"
                     }
                   }
                 }
@@ -243,7 +243,7 @@
       }
     },
     "schemaVersion": "2.0.0",
-    "sdkVersion": "kfp-1.6.0-rc.0"
+    "sdkVersion": "kfp-1.6.3"
   },
   "runtimeConfig": {
     "gcsOutputDirectory": "dummy_root"
diff --git a/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.py b/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.py
--- a/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.py
+++ b/sdk/python/kfp/v2/compiler_cli_tests/test_data/lightweight_python_functions_v2_pipeline.py
@@ -121,7 +121,7 @@ def pipeline(message: str):
       input_bool=preprocess_task.outputs['output_bool_parameter'],
       input_dict=preprocess_task.outputs['output_dict_parameter'],
       input_list=preprocess_task.outputs['output_list_parameter'],
-      num_steps=5)
+  )
 
 
 if __name__ == '__main__':
diff --git a/sdk/python/kfp/v2/compiler_cli_tests/test_data/xgboost_sample_pipeline.json b/sdk/python/kfp/v2/compiler_cli_tests/test_data/xgboost_sample_pipeline.json
--- a/sdk/python/kfp/v2/compiler_cli_tests/test_data/xgboost_sample_pipeline.json
+++ b/sdk/python/kfp/v2/compiler_cli_tests/test_data/xgboost_sample_pipeline.json
@@ -185,9 +185,21 @@
             }
           },
           "parameters": {
+            "booster": {
+              "type": "STRING"
+            },
             "label_column": {
               "type": "INT"
             },
+            "learning_rate": {
+              "type": "DOUBLE"
+            },
+            "max_depth": {
+              "type": "INT"
+            },
+            "min_split_loss": {
+              "type": "DOUBLE"
+            },
             "num_iterations": {
               "type": "INT"
             },
@@ -222,9 +234,21 @@
             }
           },
           "parameters": {
+            "booster": {
+              "type": "STRING"
+            },
             "label_column_name": {
               "type": "STRING"
             },
+            "learning_rate": {
+              "type": "DOUBLE"
+            },
+            "max_depth": {
+              "type": "INT"
+            },
+            "min_split_loss": {
+              "type": "DOUBLE"
+            },
             "num_iterations": {
               "type": "INT"
             },
@@ -393,6 +417,14 @@
               "{{$.inputs.parameters['num_iterations']}}",
               "--objective",
               "{{$.inputs.parameters['objective']}}",
+              "--booster",
+              "{{$.inputs.parameters['booster']}}",
+              "--learning-rate",
+              "{{$.inputs.parameters['learning_rate']}}",
+              "--min-split-loss",
+              "{{$.inputs.parameters['min_split_loss']}}",
+              "--max-depth",
+              "{{$.inputs.parameters['max_depth']}}",
               "--model",
               "{{$.outputs.artifacts['model'].path}}",
               "--model-config",
@@ -421,6 +453,14 @@
               "{{$.inputs.parameters['num_iterations']}}",
               "--objective",
               "{{$.inputs.parameters['objective']}}",
+              "--booster",
+              "{{$.inputs.parameters['booster']}}",
+              "--learning-rate",
+              "{{$.inputs.parameters['learning_rate']}}",
+              "--min-split-loss",
+              "{{$.inputs.parameters['min_split_loss']}}",
+              "--max-depth",
+              "{{$.inputs.parameters['max_depth']}}",
               "--model",
               "{{$.outputs.artifacts['model'].path}}",
               "--model-config",
@@ -672,6 +712,13 @@
                 }
               },
               "parameters": {
+                "booster": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "stringValue": "gbtree"
+                    }
+                  }
+                },
                 "label_column": {
                   "runtimeValue": {
                     "constantValue": {
@@ -679,6 +726,27 @@
                     }
                   }
                 },
+                "learning_rate": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "doubleValue": 0.3
+                    }
+                  }
+                },
+                "max_depth": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "intValue": "6"
+                    }
+                  }
+                },
+                "min_split_loss": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "doubleValue": 0.0
+                    }
+                  }
+                },
                 "num_iterations": {
                   "runtimeValue": {
                     "constantValue": {
@@ -716,6 +784,13 @@
                 }
               },
               "parameters": {
+                "booster": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "stringValue": "gbtree"
+                    }
+                  }
+                },
                 "label_column_name": {
                   "runtimeValue": {
                     "constantValue": {
@@ -723,6 +798,27 @@
                     }
                   }
                 },
+                "learning_rate": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "doubleValue": 0.3
+                    }
+                  }
+                },
+                "max_depth": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "intValue": "6"
+                    }
+                  }
+                },
+                "min_split_loss": {
+                  "runtimeValue": {
+                    "constantValue": {
+                      "doubleValue": 0.0
+                    }
+                  }
+                },
                 "num_iterations": {
                   "runtimeValue": {
                     "constantValue": {
@@ -747,7 +843,7 @@
       }
     },
     "schemaVersion": "2.0.0",
-    "sdkVersion": "kfp-1.6.0-rc.0"
+    "sdkVersion": "kfp-1.6.3"
   },
   "runtimeConfig": {
     "gcsOutputDirectory": "dummy_root"