diff --git a/.github/workflows/backend-visualization.yml b/.github/workflows/backend-visualization.yml index 8df4ff0c7a6e..7038278f6195 100644 --- a/.github/workflows/backend-visualization.yml +++ b/.github/workflows/backend-visualization.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.9' - name: Run tests run: ./test/presubmit-backend-visualization.sh diff --git a/.github/workflows/kfp-kubernetes-library-test.yml b/.github/workflows/kfp-kubernetes-library-test.yml index f1ac56e1eea8..aeaa341cd2ce 100644 --- a/.github/workflows/kfp-kubernetes-library-test.yml +++ b/.github/workflows/kfp-kubernetes-library-test.yml @@ -17,7 +17,6 @@ jobs: strategy: matrix: python: [ - { 'version': '3.8' }, { 'version': '3.9' }, { 'version': '3.10' }, { 'version': '3.11' }, diff --git a/.github/workflows/kfp-sdk-runtime-tests.yml b/.github/workflows/kfp-sdk-runtime-tests.yml index 14a419a780fc..6655227a20d1 100644 --- a/.github/workflows/kfp-sdk-runtime-tests.yml +++ b/.github/workflows/kfp-sdk-runtime-tests.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python: ['3.9', '3.10', '3.11', '3.12'] steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/.github/workflows/kfp-sdk-tests.yml b/.github/workflows/kfp-sdk-tests.yml index 49ff474bd25f..0f0266d8f5d4 100644 --- a/.github/workflows/kfp-sdk-tests.yml +++ b/.github/workflows/kfp-sdk-tests.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.9, 3.10, 3.11, 3.12] + python-version: [3.9, 3.10, 3.11, 3.12] steps: - name: Checkout code diff --git a/.github/workflows/kubeflow-pipelines-integration-v2.yml b/.github/workflows/kubeflow-pipelines-integration-v2.yml index 0afa4161701e..f7e43b7c496c 100644 --- a/.github/workflows/kubeflow-pipelines-integration-v2.yml +++ b/.github/workflows/kubeflow-pipelines-integration-v2.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8] + python-version: [3.9] steps: - name: Checkout code diff --git a/.github/workflows/sdk-component-yaml.yml b/.github/workflows/sdk-component-yaml.yml index 316ce85caca1..11adbcfe1f34 100644 --- a/.github/workflows/sdk-component-yaml.yml +++ b/.github/workflows/sdk-component-yaml.yml @@ -22,7 +22,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: apt-get update run: sudo apt-get update diff --git a/.github/workflows/sdk-docformatter.yml b/.github/workflows/sdk-docformatter.yml index 83b583ca3aaa..12b1c29d7051 100644 --- a/.github/workflows/sdk-docformatter.yml +++ b/.github/workflows/sdk-docformatter.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: Run docformatter tests run: ./test/presubmit-docformatter-sdk.sh diff --git a/.github/workflows/sdk-isort.yml b/.github/workflows/sdk-isort.yml index 05124d193782..527cff1096aa 100644 --- a/.github/workflows/sdk-isort.yml +++ b/.github/workflows/sdk-isort.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: Run isort tests run: ./test/presubmit-isort-sdk.sh diff --git a/.github/workflows/sdk-upgrade.yml b/.github/workflows/sdk-upgrade.yml index 9d8a7714c463..e35b7358ceb6 100644 --- a/.github/workflows/sdk-upgrade.yml +++ b/.github/workflows/sdk-upgrade.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: Run SDK upgrade tests run: ./test/presubmit-test-sdk-upgrade.sh diff --git a/.github/workflows/sdk-yapf.yml b/.github/workflows/sdk-yapf.yml index 24a6782fbe76..b1c46085ea30 100644 --- a/.github/workflows/sdk-yapf.yml +++ b/.github/workflows/sdk-yapf.yml @@ -27,7 +27,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.9' - name: Install dependencies run: pip install yapf diff --git a/.readthedocs.yml b/.readthedocs.yml index 1ccb2b2388ec..a1d632dcc990 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -8,4 +8,4 @@ python: build: os: ubuntu-22.04 tools: - python: "3.8" + python: "3.9" diff --git a/RELEASE.md b/RELEASE.md index 76b72e3f6bbc..1986d05cafb3 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -291,7 +291,7 @@ fill in the description. Detailed steps:
        To deploy Kubeflow Pipelines in an existing cluster, follow the instruction in [here](https://www.kubeflow.org/docs/pipelines/standalone-deployment-gcp/) or via UI [here](https://console.cloud.google.com/ai-platform/pipelines)
 
-       Install python SDK (python 3.7 above) by running:
+       Install python SDK (python 3.9 above) by running:
 
        ```bash
        python3 -m pip install kfp kfp-server-api --upgrade
@@ -306,7 +306,7 @@ fill in the description. Detailed steps:
        
         To deploy Kubeflow Pipelines in an existing cluster, follow the instruction in [here](https://www.kubeflow.org/docs/pipelines/standalone-deployment-gcp/).
 
-        Install kfp-server-api package (python 3.7 above) by running:
+        Install kfp-server-api package (python 3.9 above) by running:
 
         ```bash
         python3 -m pip install kfp-server-api==$VERSION --upgrade
diff --git a/api/v2alpha1/python/setup.py b/api/v2alpha1/python/setup.py
index 14be4897d94b..53ad2bc82e7f 100644
--- a/api/v2alpha1/python/setup.py
+++ b/api/v2alpha1/python/setup.py
@@ -25,7 +25,7 @@
     author_email='kubeflow-pipelines@google.com',
     url='https://github.com/kubeflow/pipelines',
     packages=setuptools.find_namespace_packages(include=['kfp.*']),
-    python_requires='>=3.7.0,<3.13.0',
+    python_requires='>=3.9.0,<3.13.0',
     install_requires=['protobuf>=4.21.1,<5'],
     include_package_data=True,
     license='Apache 2.0',
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 559e3655bf7b..fc8d1ca84676 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -27,7 +27,7 @@ RUN go-licenses csv ./backend/src/apiserver > /tmp/licenses.csv && \
   go-licenses save ./backend/src/apiserver --save_path /tmp/NOTICES
 
 # 2. Compile preloaded pipeline samples
-FROM python:3.8 as compiler
+FROM python:3.9 as compiler
 RUN apt-get update -y && apt-get install --no-install-recommends -y -q default-jdk python3-setuptools python3-dev jq
 RUN wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py
 COPY backend/requirements.txt .
diff --git a/backend/Dockerfile.conformance b/backend/Dockerfile.conformance
index 9a2920a580db..60cad80b368c 100644
--- a/backend/Dockerfile.conformance
+++ b/backend/Dockerfile.conformance
@@ -34,7 +34,7 @@ RUN chmod +x /test/integration/run.sh
 RUN tar -czvf /test.tar.gz /test
 
 
-FROM alpine:3.8
+FROM alpine:3.9
 
 COPY --from=builder /test.tar.gz /
 RUN tar -xzvf /test.tar.gz
diff --git a/backend/api/v1beta1/python_http_client/.gitlab-ci.yml b/backend/api/v1beta1/python_http_client/.gitlab-ci.yml
deleted file mode 100644
index 1098a4acf217..000000000000
--- a/backend/api/v1beta1/python_http_client/.gitlab-ci.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-# ref: https://docs.gitlab.com/ee/ci/README.html
-
-stages:
-  - test
-
-.nosetest:
-  stage: test
-  script:
-   - pip install -r requirements.txt
-   - pip install -r test-requirements.txt
-   - pytest --cov=kfp_server_api
-
-nosetest-2.7:
-  extends: .nosetest
-  image: python:2.7-alpine
-nosetest-3.3:
-  extends: .nosetest
-  image: python:3.3-alpine
-nosetest-3.4:
-  extends: .nosetest
-  image: python:3.4-alpine
-nosetest-3.5:
-  extends: .nosetest
-  image: python:3.5-alpine
-nosetest-3.6:
-  extends: .nosetest
-  image: python:3.6-alpine
-nosetest-3.7:
-  extends: .nosetest
-  image: python:3.7-alpine
-nosetest-3.8:
-  extends: .nosetest
-  image: python:3.8-alpine
diff --git a/backend/api/v1beta1/python_http_client/.travis.yml b/backend/api/v1beta1/python_http_client/.travis.yml
deleted file mode 100644
index 7f278fb3d117..000000000000
--- a/backend/api/v1beta1/python_http_client/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# ref: https://docs.travis-ci.com/user/languages/python
-language: python
-python:
-  - "2.7"
-  - "3.2"
-  - "3.3"
-  - "3.4"
-  - "3.5"
-  - "3.6"
-  - "3.7"
-  - "3.8"
-# command to install dependencies
-install:
-  - "pip install -r requirements.txt"
-  - "pip install -r test-requirements.txt"
-# command to run tests
-script: pytest --cov=kfp_server_api
diff --git a/backend/api/v2beta1/python_http_client/.gitlab-ci.yml b/backend/api/v2beta1/python_http_client/.gitlab-ci.yml
deleted file mode 100644
index 1098a4acf217..000000000000
--- a/backend/api/v2beta1/python_http_client/.gitlab-ci.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-# ref: https://docs.gitlab.com/ee/ci/README.html
-
-stages:
-  - test
-
-.nosetest:
-  stage: test
-  script:
-   - pip install -r requirements.txt
-   - pip install -r test-requirements.txt
-   - pytest --cov=kfp_server_api
-
-nosetest-2.7:
-  extends: .nosetest
-  image: python:2.7-alpine
-nosetest-3.3:
-  extends: .nosetest
-  image: python:3.3-alpine
-nosetest-3.4:
-  extends: .nosetest
-  image: python:3.4-alpine
-nosetest-3.5:
-  extends: .nosetest
-  image: python:3.5-alpine
-nosetest-3.6:
-  extends: .nosetest
-  image: python:3.6-alpine
-nosetest-3.7:
-  extends: .nosetest
-  image: python:3.7-alpine
-nosetest-3.8:
-  extends: .nosetest
-  image: python:3.8-alpine
diff --git a/backend/api/v2beta1/python_http_client/.travis.yml b/backend/api/v2beta1/python_http_client/.travis.yml
deleted file mode 100644
index 7f278fb3d117..000000000000
--- a/backend/api/v2beta1/python_http_client/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# ref: https://docs.travis-ci.com/user/languages/python
-language: python
-python:
-  - "2.7"
-  - "3.2"
-  - "3.3"
-  - "3.4"
-  - "3.5"
-  - "3.6"
-  - "3.7"
-  - "3.8"
-# command to install dependencies
-install:
-  - "pip install -r requirements.txt"
-  - "pip install -r test-requirements.txt"
-# command to run tests
-script: pytest --cov=kfp_server_api
diff --git a/backend/metadata_writer/Dockerfile b/backend/metadata_writer/Dockerfile
index 63394179eca7..749807d3666c 100644
--- a/backend/metadata_writer/Dockerfile
+++ b/backend/metadata_writer/Dockerfile
@@ -1,5 +1,5 @@
 # ml-metadata package depends on tensorflow package
-FROM python:3.8
+FROM python:3.9
 COPY backend/metadata_writer/requirements.txt /kfp/metadata_writer/
 RUN python3 -m pip install -r /kfp/metadata_writer/requirements.txt
 
diff --git a/backend/metadata_writer/requirements.txt b/backend/metadata_writer/requirements.txt
index 071621f3a8f1..15f168e684c2 100644
--- a/backend/metadata_writer/requirements.txt
+++ b/backend/metadata_writer/requirements.txt
@@ -1,5 +1,5 @@
 #
-# This file is autogenerated by pip-compile with Python 3.8
+# This file is autogenerated by pip-compile with Python 3.9
 # by the following command:
 #
 #    pip-compile --output-file=- -
diff --git a/backend/metadata_writer/update_requirements.sh b/backend/metadata_writer/update_requirements.sh
index f63fa4972d07..a907c2a9fc5b 100755
--- a/backend/metadata_writer/update_requirements.sh
+++ b/backend/metadata_writer/update_requirements.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
 
 # This image should be in sync with Dockerfile.
-IMAGE="python:3.8"
+IMAGE="python:3.9"
 ../../hack/update-requirements.sh $IMAGE requirements.txt
diff --git a/backend/src/apiserver/resource/resource_manager_test.go b/backend/src/apiserver/resource/resource_manager_test.go
index c1221ec6caac..6a44c229eaf1 100644
--- a/backend/src/apiserver/resource/resource_manager_test.go
+++ b/backend/src/apiserver/resource/resource_manager_test.go
@@ -3512,7 +3512,7 @@ spec:
       - name: ENABLE_CACHING
         valueFrom:
           fieldRef: {fieldPath: 'metadata.labels[''pipelines.kubeflow.org/enable_caching'']'}
-      - {name: KFP_V2_IMAGE, value: 'python:3.7'}
+      - {name: KFP_V2_IMAGE, value: 'python:3.9'}
       - {name: KFP_V2_RUNTIME_INFO, value: '{"inputParameters": {"num_steps": {"type":
           "INT"}}, "inputArtifacts": {"dataset": {"metadataPath": "/tmp/inputs/dataset/data",
           "schemaTitle": "system.Dataset", "instanceSchema": ""}}, "outputParameters":
@@ -3520,7 +3520,7 @@ spec:
           "", "metadataPath": "/tmp/outputs/model/data"}}}'}
       envFrom:
       - configMapRef: {name: metadata-grpc-configmap, optional: true}
-      image: python:3.7
+      image: python:3.9
       volumeMounts:
       - {mountPath: /kfp-launcher, name: kfp-launcher}
     inputs:
@@ -4044,7 +4044,7 @@ deploymentSpec:
           _parsed_args = vars(_parser.parse_args())
 
           _outputs = hello_world(**_parsed_args)
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-world
 root:
@@ -4077,7 +4077,7 @@ deploymentSpec:
   executors:
     exec-hello-world:
       container:
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: pipelines/p1/versions/v1
 root:
diff --git a/backend/src/apiserver/resource/resource_manager_util_test.go b/backend/src/apiserver/resource/resource_manager_util_test.go
index 46889b870095..8796b8716060 100644
--- a/backend/src/apiserver/resource/resource_manager_util_test.go
+++ b/backend/src/apiserver/resource/resource_manager_util_test.go
@@ -68,7 +68,7 @@ spec:
       command:
       - python
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
       name: ""
       resources: {}
     inputs: {}
@@ -181,7 +181,7 @@ spec:
       command:
       - python
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
       name: ""
       resources: {}
     inputs: {}
diff --git a/backend/src/apiserver/server/pipeline_upload_server_test.go b/backend/src/apiserver/server/pipeline_upload_server_test.go
index e26eed60b93d..87c140662e83 100644
--- a/backend/src/apiserver/server/pipeline_upload_server_test.go
+++ b/backend/src/apiserver/server/pipeline_upload_server_test.go
@@ -667,7 +667,7 @@ deploymentSpec:
           _parsed_args = vars(_parser.parse_args())
 
           _outputs = hello_world(**_parsed_args)
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-world
 root:
@@ -724,7 +724,7 @@ deploymentSpec:
           _parsed_args = vars(_parser.parse_args())
 
           _outputs = hello_world(**_parsed_args)
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-world
 root:
@@ -765,7 +765,7 @@ deploymentSpec:
   executors:
     exec-hello-world:
       container:
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-world-
 root:
@@ -790,7 +790,7 @@ deploymentSpec:
   executors:
     exec-hello-world:
       container:
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hEllo-world
 root:
@@ -815,7 +815,7 @@ deploymentSpec:
   executors:
     exec-hello-world:
       container:
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: more than  128 characters more than  128 characters more than  128 characters more than  128 characters more than  128 characters
 root:
@@ -840,7 +840,7 @@ deploymentSpec:
   executors:
     exec-hello-world:
       container:
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-worl.d
 root:
diff --git a/backend/src/apiserver/server/test/pipeline_with_volume.yaml b/backend/src/apiserver/server/test/pipeline_with_volume.yaml
index 809b3208895d..99c0009236b4 100644
--- a/backend/src/apiserver/server/test/pipeline_with_volume.yaml
+++ b/backend/src/apiserver/server/test/pipeline_with_volume.yaml
@@ -66,7 +66,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-comp-2:
       container:
         args:
@@ -92,7 +92,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-comp-3:
       container:
         args:
@@ -118,7 +118,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-createpvc:
       container:
         image: argostub/createpvc
diff --git a/backend/src/apiserver/server/test/v2-hello-world.json b/backend/src/apiserver/server/test/v2-hello-world.json
index d7a375c4ccae..bff7b6b7b2a7 100644
--- a/backend/src/apiserver/server/test/v2-hello-world.json
+++ b/backend/src/apiserver/server/test/v2-hello-world.json
@@ -22,7 +22,7 @@
               "program_path=$(mktemp)\nprintf \"%s\" \"$0\" > \"$program_path\"\npython3 -u \"$program_path\" \"$@\"\n",
               "def hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser = argparse.ArgumentParser(prog='Hello world', description='')\n_parser.add_argument(\"--text\", dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"
             ],
-            "image": "python:3.7"
+            "image": "python:3.9"
           }
         }
       }
diff --git a/backend/src/apiserver/server/test/xgboost_sample_pipeline.yaml b/backend/src/apiserver/server/test/xgboost_sample_pipeline.yaml
index e7d2be1cc355..67354ed309c8 100644
--- a/backend/src/apiserver/server/test/xgboost_sample_pipeline.yaml
+++ b/backend/src/apiserver/server/test/xgboost_sample_pipeline.yaml
@@ -293,7 +293,7 @@ deploymentSpec:
           \    try:\n        os.makedirs(os.path.dirname(output_file))\n    except\
           \ OSError:\n        pass\n    with open(output_file, 'w') as f:\n      \
           \  f.write(_output_serializers[idx](_outputs[idx]))\n"
-        image: python:3.7
+        image: python:3.9
     exec-xgboost-predict:
       container:
         args:
@@ -344,7 +344,7 @@ deploymentSpec:
           _parser.add_argument(\"--predictions\", dest=\"predictions_path\", type=_make_parent_dirs_and_return_path,\
           \ required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
           \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
+        image: python:3.9
     exec-xgboost-predict-2:
       container:
         args:
@@ -398,7 +398,7 @@ deploymentSpec:
           predictions_path\", type=_make_parent_dirs_and_return_path, required=True,\
           \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
           \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
+        image: python:3.9
     exec-xgboost-predict-3:
       container:
         args:
@@ -452,7 +452,7 @@ deploymentSpec:
           predictions_path\", type=_make_parent_dirs_and_return_path, required=True,\
           \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
           \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
+        image: python:3.9
     exec-xgboost-predict-4:
       container:
         args:
@@ -503,7 +503,7 @@ deploymentSpec:
           _parser.add_argument(\"--predictions\", dest=\"predictions_path\", type=_make_parent_dirs_and_return_path,\
           \ required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
           \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
+        image: python:3.9
     exec-xgboost-train:
       container:
         args:
@@ -620,7 +620,7 @@ deploymentSpec:
           , dest=\"model_config_path\", type=_make_parent_dirs_and_return_path, required=True,\
           \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
           \n_outputs = xgboost_train(**_parsed_args)\n"
-        image: python:3.7
+        image: python:3.9
     exec-xgboost-train-2:
       container:
         args:
@@ -737,7 +737,7 @@ deploymentSpec:
           , dest=\"model_config_path\", type=_make_parent_dirs_and_return_path, required=True,\
           \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
           \n_outputs = xgboost_train(**_parsed_args)\n"
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: xgboost-sample-pipeline
 root:
diff --git a/backend/src/apiserver/storage/pipeline_store_test.go b/backend/src/apiserver/storage/pipeline_store_test.go
index 677df7b48250..6a04827e55bd 100644
--- a/backend/src/apiserver/storage/pipeline_store_test.go
+++ b/backend/src/apiserver/storage/pipeline_store_test.go
@@ -1936,7 +1936,7 @@ executors:
 		_parsed_args = vars(_parser.parse_args())
 
 		_outputs = hello_world(**_parsed_args)
-	  image: python:3.7
+	  image: python:3.9
 pipelineInfo:
 name: hello-world
 root:
diff --git a/backend/src/apiserver/template/testdata/hello_world.yaml b/backend/src/apiserver/template/testdata/hello_world.yaml
index 5753b04846c1..8f37ce800980 100644
--- a/backend/src/apiserver/template/testdata/hello_world.yaml
+++ b/backend/src/apiserver/template/testdata/hello_world.yaml
@@ -31,7 +31,7 @@ deploymentSpec:
           _parsed_args = vars(_parser.parse_args())
 
           _outputs = hello_world(**_parsed_args)
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: namespace/n1/pipeline/hello-world
 root:
diff --git a/backend/src/apiserver/template/testdata/hello_world_schema_2_0_0.yaml b/backend/src/apiserver/template/testdata/hello_world_schema_2_0_0.yaml
index 14c571d27317..ac46b6c1aa3c 100644
--- a/backend/src/apiserver/template/testdata/hello_world_schema_2_0_0.yaml
+++ b/backend/src/apiserver/template/testdata/hello_world_schema_2_0_0.yaml
@@ -30,7 +30,7 @@ deploymentSpec:
           _parsed_args = vars(_parser.parse_args())
 
           _outputs = hello_world(**_parsed_args)
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-world
 root:
diff --git a/backend/src/apiserver/template/testdata/pipeline_with_volume.yaml b/backend/src/apiserver/template/testdata/pipeline_with_volume.yaml
index 3f612a8954f6..64247b4bbffb 100644
--- a/backend/src/apiserver/template/testdata/pipeline_with_volume.yaml
+++ b/backend/src/apiserver/template/testdata/pipeline_with_volume.yaml
@@ -68,7 +68,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-comp-2:
       container:
         args:
@@ -94,7 +94,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-comp-3:
       container:
         args:
@@ -120,7 +120,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-createpvc:
       container:
         image: argostub/createpvc
diff --git a/backend/src/apiserver/visualization/requirements.in b/backend/src/apiserver/visualization/requirements.in
index 61ebd737bad7..4639a05a2f6b 100644
--- a/backend/src/apiserver/visualization/requirements.in
+++ b/backend/src/apiserver/visualization/requirements.in
@@ -8,7 +8,7 @@ jinja2==2.11.3
 jupyter_client==5.3.*
 markupsafe==2.0.1
 nbconvert==5.5.0
-nbformat==4.4.0
+nbformat==5.10.4
 scikit-learn==0.24.2
 tensorflow==2.10.1
 tensorflow-metadata==1.9.*
diff --git a/backend/src/apiserver/visualization/requirements.txt b/backend/src/apiserver/visualization/requirements.txt
index 00cc9a82e4a3..25c6922ce092 100644
--- a/backend/src/apiserver/visualization/requirements.txt
+++ b/backend/src/apiserver/visualization/requirements.txt
@@ -1,5 +1,5 @@
 #
-# This file is autogenerated by pip-compile with Python 3.8
+# This file is autogenerated by pip-compile with Python 3.9
 # by the following command:
 #
 #    pip-compile --output-file=- --resolver=backtracking -
@@ -67,6 +67,8 @@ fasteners==0.19
     # via
     #   apache-beam
     #   google-apitools
+fastjsonschema==2.20.0
+    # via nbformat
 flatbuffers==23.5.26
     # via tensorflow
 gast==0.4.0
@@ -195,10 +197,6 @@ idna==3.4
     # via requests
 importlib-metadata==6.8.0
     # via markdown
-importlib-resources==6.1.0
-    # via
-    #   jsonschema
-    #   jsonschema-specifications
 ipykernel==5.1.1
     # via
     #   -r requirements.in
@@ -212,7 +210,6 @@ ipython==7.12.0
 ipython-genutils==0.2.0
     # via
     #   ipywidgets
-    #   nbformat
     #   notebook
 ipywidgets==7.8.1
     # via tensorflow-model-analysis
@@ -267,7 +264,7 @@ nbconvert==5.5.0
     # via
     #   -r requirements.in
     #   notebook
-nbformat==4.4.0
+nbformat==5.10.4
     # via
     #   -r requirements.in
     #   nbconvert
@@ -325,8 +322,6 @@ pickleshare==0.7.5
     # via ipython
 pillow==10.3.0
     # via bokeh
-pkgutil-resolve-name==1.3.10
-    # via jsonschema
 platformdirs==3.10.0
     # via jupyter-core
 prometheus-client==0.17.1
@@ -558,9 +553,7 @@ widgetsnbextension==3.6.6
 wrapt==1.15.0
     # via tensorflow
 zipp==3.17.0
-    # via
-    #   importlib-metadata
-    #   importlib-resources
+    # via importlib-metadata
 zstandard==0.21.0
     # via apache-beam
 
diff --git a/backend/src/cache/server/mutation_test.go b/backend/src/cache/server/mutation_test.go
index 5ad0fc8c1396..52d92ee27c9a 100644
--- a/backend/src/cache/server/mutation_test.go
+++ b/backend/src/cache/server/mutation_test.go
@@ -52,7 +52,7 @@ var (
 					Command: []string{"python"},
 					Env: []corev1.EnvVar{{
 						Name:  ArgoWorkflowTemplateEnvKey,
-						Value: `{"name": "Does not matter","container":{"command":["echo", "Hello"],"image":"python:3.7"}}`,
+						Value: `{"name": "Does not matter","container":{"command":["echo", "Hello"],"image":"python:3.9"}}`,
 					}},
 				},
 			},
@@ -169,9 +169,9 @@ func TestMutatePodIfCached(t *testing.T) {
 
 func TestMutatePodIfCachedWithCacheEntryExist(t *testing.T) {
 	executionCache := &model.ExecutionCache{
-		ExecutionCacheKey: "f5fe913be7a4516ebfe1b5de29bcb35edd12ecc776b2f33f10ca19709ea3b2f0",
+		ExecutionCacheKey: "1933d178a14bc415466cfd1b3ca2100af975e8c59e1ff9d502fcf18eb5cbd7f7",
 		ExecutionOutput:   "testOutput",
-		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.7"}}`,
+		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.9"}}`,
 		MaxCacheStaleness: -1,
 	}
 	fakeClientManager.CacheStore().CreateExecutionCache(executionCache)
@@ -188,9 +188,9 @@ func TestMutatePodIfCachedWithCacheEntryExist(t *testing.T) {
 
 func TestDefaultImage(t *testing.T) {
 	executionCache := &model.ExecutionCache{
-		ExecutionCacheKey: "f5fe913be7a4516ebfe1b5de29bcb35edd12ecc776b2f33f10ca19709ea3b2f0",
+		ExecutionCacheKey: "1933d178a14bc415466cfd1b3ca2100af975e8c59e1ff9d502fcf18eb5cbd7f7",
 		ExecutionOutput:   "testOutput",
-		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.7"}}`,
+		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.9"}}`,
 		MaxCacheStaleness: -1,
 	}
 	fakeClientManager.CacheStore().CreateExecutionCache(executionCache)
@@ -209,7 +209,7 @@ func TestSetImage(t *testing.T) {
 	executionCache := &model.ExecutionCache{
 		ExecutionCacheKey: "f5fe913be7a4516ebfe1b5de29bcb35edd12ecc776b2f33f10ca19709ea3b2f0",
 		ExecutionOutput:   "testOutput",
-		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.7"}}`,
+		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.9"}}`,
 		MaxCacheStaleness: -1,
 	}
 	fakeClientManager.CacheStore().CreateExecutionCache(executionCache)
@@ -226,7 +226,7 @@ func TestCacheNodeRestriction(t *testing.T) {
 	executionCache := &model.ExecutionCache{
 		ExecutionCacheKey: "f5fe913be7a4516ebfe1b5de29bcb35edd12ecc776b2f33f10ca19709ea3b2f0",
 		ExecutionOutput:   "testOutput",
-		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.7"},"nodeSelector":{"disktype":"ssd"}}`,
+		ExecutionTemplate: `{"container":{"command":["echo", "Hello"],"image":"python:3.9"},"nodeSelector":{"disktype":"ssd"}}`,
 		MaxCacheStaleness: -1,
 	}
 	fakeClientManager.CacheStore().CreateExecutionCache(executionCache)
@@ -239,9 +239,9 @@ func TestCacheNodeRestriction(t *testing.T) {
 
 func TestMutatePodIfCachedWithTeamplateCleanup(t *testing.T) {
 	executionCache := &model.ExecutionCache{
-		ExecutionCacheKey: "5a20e3f2e74863b363291953082d9812a58e25f7117bface1c76d40ef0ee88fc",
+		ExecutionCacheKey: "c81988503d55a5817d79bd972017d95c37f72b024e522b4d79787d9f599c0725",
 		ExecutionOutput:   "testOutput",
-		ExecutionTemplate: `Cache key was calculated from this: {"container":{"command":["echo", "Hello"],"image":"python:3.7"},"outputs":"anything"}`,
+		ExecutionTemplate: `Cache key was calculated from this: {"container":{"command":["echo", "Hello"],"image":"python:3.9"},"outputs":"anything"}`,
 		MaxCacheStaleness: -1,
 	}
 	fakeClientManager.CacheStore().CreateExecutionCache(executionCache)
@@ -253,7 +253,7 @@ func TestMutatePodIfCachedWithTeamplateCleanup(t *testing.T) {
 			"name": "Does not matter",
 			"metadata": "anything",
 			"container": {
-				"image": "python:3.7",
+				"image": "python:3.9",
 				"command": ["echo", "Hello"]
 			},
 			"outputs": "anything",
diff --git a/backend/src/v2/compiler/argocompiler/testdata/create_mount_delete_dynamic_pvc.yaml b/backend/src/v2/compiler/argocompiler/testdata/create_mount_delete_dynamic_pvc.yaml
index 7a5565595ed3..25b078fa55da 100644
--- a/backend/src/v2/compiler/argocompiler/testdata/create_mount_delete_dynamic_pvc.yaml
+++ b/backend/src/v2/compiler/argocompiler/testdata/create_mount_delete_dynamic_pvc.yaml
@@ -8,9 +8,9 @@ spec:
     parameters:
     - name: kubernetes-comp-comp
       value: '{"pvcMount":[{"mountPath":"/data","taskOutputParameter":{"outputParameterKey":"name","producerTask":"createpvc"}}]}'
-    - name: components-95f802401136aebf1bf728a6675d7adba5513b53673a3698e00a6d8744638080
+    - name: components-b34273359995b3746ecf1bb58ac4bd6c54d47b6fdc35b013bb7962946f322a19
       value: '{"executorLabel":"exec-comp"}'
-    - name: implementations-95f802401136aebf1bf728a6675d7adba5513b53673a3698e00a6d8744638080
+    - name: implementations-b34273359995b3746ecf1bb58ac4bd6c54d47b6fdc35b013bb7962946f322a19
       value: '{"args":["--executor_input","{{$}}","--function_to_execute","comp"],"command":["sh","-c","\nif
         ! [ -x \"$(command -v pip)\" ]; then\n    python3 -m ensurepip || python3
         -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1
@@ -18,7 +18,7 @@ spec:
         \u0026\u0026 \"$0\" \"$@\"\n","sh","-ec","program_path=$(mktemp -d) printf
         \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\" python3 -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"
         ","\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import
-        *\n\ndef comp():\n    pass\n\n"],"image":"python:3.7"}'
+        *\n\ndef comp():\n    pass\n\n"],"image":"python:3.9"}'
     - name: kubernetes-comp-comp-2
       value: '{"pvcMount":[{"mountPath":"/reused_data","taskOutputParameter":{"outputParameterKey":"name","producerTask":"createpvc"}}]}'
     - name: components-98f254581598234b59377784d6cbf209de79e0bcda8013fe4c4397b5d3a26767
@@ -197,11 +197,11 @@ spec:
       - arguments:
           parameters:
           - name: component
-            value: '{{workflow.parameters.components-95f802401136aebf1bf728a6675d7adba5513b53673a3698e00a6d8744638080}}'
+            value: '{{workflow.parameters.components-b34273359995b3746ecf1bb58ac4bd6c54d47b6fdc35b013bb7962946f322a19}}'
           - name: task
             value: '{"cachingOptions":{"enableCache":true},"componentRef":{"name":"comp-comp"},"dependentTasks":["createpvc"],"taskInfo":{"name":"comp"}}'
           - name: container
-            value: '{{workflow.parameters.implementations-95f802401136aebf1bf728a6675d7adba5513b53673a3698e00a6d8744638080}}'
+            value: '{{workflow.parameters.implementations-b34273359995b3746ecf1bb58ac4bd6c54d47b6fdc35b013bb7962946f322a19}}'
           - name: parent-dag-id
             value: '{{inputs.parameters.parent-dag-id}}'
           - name: kubernetes-config
@@ -222,11 +222,11 @@ spec:
       - arguments:
           parameters:
           - name: component
-            value: '{{workflow.parameters.components-95f802401136aebf1bf728a6675d7adba5513b53673a3698e00a6d8744638080}}'
+            value: '{{workflow.parameters.components-b34273359995b3746ecf1bb58ac4bd6c54d47b6fdc35b013bb7962946f322a19}}'
           - name: task
             value: '{"cachingOptions":{"enableCache":true},"componentRef":{"name":"comp-comp-2"},"dependentTasks":["comp","createpvc"],"taskInfo":{"name":"comp-2"}}'
           - name: container
-            value: '{{workflow.parameters.implementations-95f802401136aebf1bf728a6675d7adba5513b53673a3698e00a6d8744638080}}'
+            value: '{{workflow.parameters.implementations-b34273359995b3746ecf1bb58ac4bd6c54d47b6fdc35b013bb7962946f322a19}}'
           - name: parent-dag-id
             value: '{{inputs.parameters.parent-dag-id}}'
           - name: kubernetes-config
diff --git a/backend/src/v2/compiler/argocompiler/testdata/create_pod_metadata.yaml b/backend/src/v2/compiler/argocompiler/testdata/create_pod_metadata.yaml
index 67308ba33dda..7736012a09e4 100644
--- a/backend/src/v2/compiler/argocompiler/testdata/create_pod_metadata.yaml
+++ b/backend/src/v2/compiler/argocompiler/testdata/create_pod_metadata.yaml
@@ -8,15 +8,15 @@ spec:
     parameters:
     - name: kubernetes-comp-hello-world
       value: '{"podMetadata":{"annotations":{"experiment_id":"234567","run_id":"123456"},"labels":{"kubeflow.com/common":"test","kubeflow.com/kfp":"pipeline-node"}}}'
-    - name: components-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390
+    - name: components-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7
       value: '{"executorLabel":"exec-hello-world","inputDefinitions":{"parameters":{"text":{"type":"STRING"}}}}'
-    - name: implementations-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390
+    - name: implementations-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7
       value: '{"args":["--text","{{$.inputs.parameters[''text'']}}"],"command":["sh","-ec","program_path=$(mktemp)\nprintf
         \"%s\" \"$0\" \u003e \"$program_path\"\npython3 -u \"$program_path\" \"$@\"\n","def
         hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser
         = argparse.ArgumentParser(prog=''Hello world'', description='''')\n_parser.add_argument(\"--text\",
         dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
-        = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.7"}'
+        = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.9"}'
     - name: components-root
       value: '{"dag":{"tasks":{"hello-world":{"cachingOptions":{"enableCache":true},"componentRef":{"name":"comp-hello-world"},"inputs":{"parameters":{"text":{"componentInputParameter":"text"}}},"taskInfo":{"name":"hello-world"}}}},"inputDefinitions":{"parameters":{"text":{"type":"STRING"}}}}'
   entrypoint: entrypoint
@@ -191,11 +191,11 @@ spec:
       - arguments:
           parameters:
           - name: component
-            value: '{{workflow.parameters.components-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390}}'
+            value: '{{workflow.parameters.components-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7}}'
           - name: task
             value: '{"cachingOptions":{"enableCache":true},"componentRef":{"name":"comp-hello-world"},"inputs":{"parameters":{"text":{"componentInputParameter":"text"}}},"taskInfo":{"name":"hello-world"}}'
           - name: container
-            value: '{{workflow.parameters.implementations-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390}}'
+            value: '{{workflow.parameters.implementations-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7}}'
           - name: parent-dag-id
             value: '{{inputs.parameters.parent-dag-id}}'
           - name: kubernetes-config
diff --git a/backend/src/v2/compiler/argocompiler/testdata/hello_world.yaml b/backend/src/v2/compiler/argocompiler/testdata/hello_world.yaml
index 6bc59366d8d9..af2e8eebd216 100644
--- a/backend/src/v2/compiler/argocompiler/testdata/hello_world.yaml
+++ b/backend/src/v2/compiler/argocompiler/testdata/hello_world.yaml
@@ -6,15 +6,15 @@ metadata:
 spec:
   arguments:
     parameters:
-    - name: components-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390
+    - name: components-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7
       value: '{"executorLabel":"exec-hello-world","inputDefinitions":{"parameters":{"text":{"type":"STRING"}}}}'
-    - name: implementations-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390
+    - name: implementations-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7
       value: '{"args":["--text","{{$.inputs.parameters[''text'']}}"],"command":["sh","-ec","program_path=$(mktemp)\nprintf
         \"%s\" \"$0\" \u003e \"$program_path\"\npython3 -u \"$program_path\" \"$@\"\n","def
         hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser
         = argparse.ArgumentParser(prog=''Hello world'', description='''')\n_parser.add_argument(\"--text\",
         dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
-        = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.7"}'
+        = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.9"}'
     - name: components-root
       value: '{"dag":{"tasks":{"hello-world":{"cachingOptions":{"enableCache":true},"componentRef":{"name":"comp-hello-world"},"inputs":{"parameters":{"text":{"componentInputParameter":"text"}}},"taskInfo":{"name":"hello-world"}}}},"inputDefinitions":{"parameters":{"text":{"type":"STRING"}}}}'
   entrypoint: entrypoint
@@ -183,11 +183,11 @@ spec:
       - arguments:
           parameters:
           - name: component
-            value: '{{workflow.parameters.components-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390}}'
+            value: '{{workflow.parameters.components-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7}}'
           - name: task
             value: '{"cachingOptions":{"enableCache":true},"componentRef":{"name":"comp-hello-world"},"inputs":{"parameters":{"text":{"componentInputParameter":"text"}}},"taskInfo":{"name":"hello-world"}}'
           - name: container
-            value: '{{workflow.parameters.implementations-34e222d692a0573c88000b8cb02ad24423491a53e061e9bba36d3718dd4c3390}}'
+            value: '{{workflow.parameters.implementations-203fce8adabe0cfa7da54b9d3ff79c772136c926974659b51c378727c7ccdfb7}}'
           - name: parent-dag-id
             value: '{{inputs.parameters.parent-dag-id}}'
         name: hello-world-driver
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/condition_ir.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/condition_ir.yaml
index 4eeb48af8d58..143d178fac81 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/condition_ir.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/condition_ir.yaml
@@ -114,7 +114,7 @@ pipelineSpec:
             \ a coin and output heads or tails randomly.\"\"\"\n    if force_flip_result:\n\
             \        return force_flip_result\n    import random\n    result = 'heads'\
             \ if random.randint(0, 1) == 0 else 'tails'\n    return result\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-flip-coin-2:
         container:
           args:
@@ -143,7 +143,7 @@ pipelineSpec:
             \ a coin and output heads or tails randomly.\"\"\"\n    if force_flip_result:\n\
             \        return force_flip_result\n    import random\n    result = 'heads'\
             \ if random.randint(0, 1) == 0 else 'tails'\n    return result\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-print-msg:
         container:
           args:
@@ -170,7 +170,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_msg(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
             \n"
-          image: python:3.7
+          image: python:3.9
       exec-print-msg-2:
         container:
           args:
@@ -197,7 +197,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_msg(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
             \n"
-          image: python:3.7
+          image: python:3.9
       exec-print-msg-3:
         container:
           args:
@@ -224,7 +224,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_msg(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
             \n"
-          image: python:3.7
+          image: python:3.9
   pipelineInfo:
     name: condition-v2
   root:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler.yaml
index 3b2568eca091..30f68e10b7ab 100755
--- a/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler.yaml
@@ -49,7 +49,7 @@ spec:
                   -d)\nprintf \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\"\npython3
                   -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
                   kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import
-                  *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.7"}'
+                  *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.9"}'
               - name: iteration-index
                 value: ""
               - name: kubernetes-config
@@ -166,7 +166,7 @@ spec:
                       - configMapRef:
                           name: metadata-grpc-configmap
                           optional: true
-                      image: python:3.7
+                      image: python:3.9
                       name: user-main
             - name: root-system-dag-pub-driver
               params:
@@ -210,7 +210,7 @@ spec:
           \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\"\npython3 -m
           kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
           kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef
-          fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n    print(message)\n    sys.exit(1)\n\n"],"image":"python:3.7"}'
+          fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n    print(message)\n    sys.exit(1)\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -329,7 +329,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: print-op-2
       params:
@@ -352,7 +352,7 @@ spec:
           \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\"\npython3 -m
           kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
           kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef
-          print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.7"}'
+          print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -469,7 +469,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: exit-handler-1-dag-driver
       params:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler_ir.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler_ir.yaml
index f42800c71773..45aeae7cc764 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler_ir.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/exit_handler_ir.yaml
@@ -76,7 +76,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n\
             \    print(message)\n    sys.exit(1)\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-print-op:
         container:
           args:
@@ -103,7 +103,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
             \    print(message)\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-print-op-2:
         container:
           args:
@@ -130,7 +130,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
             \    print(message)\n\n"
-          image: python:3.7
+          image: python:3.9
   pipelineInfo:
     name: pipeline-with-exit-handler
   root:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/hello_world.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/hello_world.yaml
index bb5490da0be8..bd0ab351ce57 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/hello_world.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/hello_world.yaml
@@ -31,7 +31,7 @@ spec:
           hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser
           = argparse.ArgumentParser(prog=''Hello world'', description='''')\n_parser.add_argument(\"--text\",
           dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
-          = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.7"}'
+          = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -137,7 +137,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: root-system-dag-driver
       params:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/loop_static.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/loop_static.yaml
index 0bb2b7db3144..30b35248cd58 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/loop_static.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/loop_static.yaml
@@ -78,7 +78,7 @@ spec:
                   -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
                   kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import
                   *\n\ndef concat_op(a: str, b: str) -\u003e str:\n    print(a + b)\n    return
-                  a + b\n\n"],"image":"python:3.7"}'
+                  a + b\n\n"],"image":"python:3.9"}'
               - name: iteration-index
                 value: ""
               - name: kubernetes-config
@@ -195,7 +195,7 @@ spec:
                       - configMapRef:
                           name: metadata-grpc-configmap
                           optional: true
-                      image: python:3.7
+                      image: python:3.9
                       name: user-main
             - name: print-op-2
               params:
@@ -219,7 +219,7 @@ spec:
                   -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
                   kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import
                   *\n\ndef print_op(text: str) -\u003e str:\n    print(text)\n    return
-                  text\n\n"],"image":"python:3.7"}'
+                  text\n\n"],"image":"python:3.9"}'
               - name: iteration-index
                 value: ""
               - name: kubernetes-config
@@ -338,7 +338,7 @@ spec:
                       - configMapRef:
                           name: metadata-grpc-configmap
                           optional: true
-                      image: python:3.7
+                      image: python:3.9
                       name: user-main
     - name: for-loop-2-dag-driver
       params:
@@ -406,7 +406,7 @@ spec:
           \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\"\npython3 -m
           kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
           kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef
-          print_op(text: str) -\u003e str:\n    print(text)\n    return text\n\n"],"image":"python:3.7"}'
+          print_op(text: str) -\u003e str:\n    print(text)\n    return text\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -523,7 +523,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: root-system-dag-driver
       params:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/loop_static_ir.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/loop_static_ir.yaml
index fd6af49a6ade..13d9b22e3888 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/loop_static_ir.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/loop_static_ir.yaml
@@ -101,7 +101,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef concat_op(a: str, b: str) -> str:\n    print(a + b)\n    return\
             \ a + b\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-print-op:
         container:
           args:
@@ -128,7 +128,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_op(text: str) -> str:\n    print(text)\n    return text\n\
             \n"
-          image: python:3.7
+          image: python:3.9
       exec-print-op-2:
         container:
           args:
@@ -155,7 +155,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_op(text: str) -> str:\n    print(text)\n    return text\n\
             \n"
-          image: python:3.7
+          image: python:3.9
   pipelineInfo:
     name: pipeline-with-loop-static
   root:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline.yaml
index 7cbe60e2ba2a..559d460b1a2d 100755
--- a/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline.yaml
@@ -37,7 +37,7 @@ spec:
           convert_experiment_spec_to_str(experiment_spec_json: Dict[str, str])-\u003e
           NamedTuple(''Outputs'', [(''experiment_spec_str_output'', str)]):\n    import
           json\n    output = NamedTuple(''Outputs'', [(''experiment_spec_str_output'',
-          str)])\n    return output(json.dumps(experiment_spec_json))\n\n"],"image":"python:3.7"}'
+          str)])\n    return output(json.dumps(experiment_spec_json))\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -157,7 +157,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: convert-katib-results
       params:
@@ -188,7 +188,7 @@ spec:
           pa[\"name\"] == \"learning_rate\":\n            best_hps.append(\"--tf-learning-rate=\"
           + pa[\"value\"])\n        elif pa[\"name\"] == \"batch_size\":\n            best_hps.append(\"--tf-batch-size=\"
           + pa[\"value\"])\n    print(\"Best Hyperparameters: {}\".format(best_hps))\n    return
-          \" \".join(best_hps)\n\n"],"image":"python:3.7"}'
+          \" \".join(best_hps)\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -321,7 +321,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: create-dataset
       params:
@@ -501,7 +501,7 @@ spec:
           Create an Experiment from the above parameters.\n    experiment_spec = V1beta1ExperimentSpec(\n        max_trial_count=max_trial_count,\n        max_failed_trial_count=max_failed_trial_count,\n        parallel_trial_count=parallel_trial_count,\n        objective=objective,\n        algorithm=algorithm,\n        parameters=parameters,\n        trial_template=trial_template\n    )\n\n    #
           Convert experiment_spec to Dict type.\n    experiment_spec_json = ApiClient().sanitize_for_serialization(experiment_spec)\n    output
           = NamedTuple(''Outputs'', [(''experiment_spec_json'', Dict[str, str])])\n    return
-          output(experiment_spec_json)\n\n"],"image":"python:3.8"}'
+          output(experiment_spec_json)\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -761,7 +761,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.8
+              image: python:3.9
               name: user-main
     - name: create-tfjob-task
       params:
@@ -812,7 +812,7 @@ spec:
           [\n                          \"python /opt/model.py --tf-export-dir=/mnt/export
           --tf-train-steps={} {}\".format(training_steps, best_hps) \n                        ],\n                    }\n                ],\n            }\n        }\n    }\n\n    output
           = NamedTuple(''Outputs'', [(''chief_spec'', Dict[str, str]), (''worker_spec'',
-          Dict[str, str])])\n    return output(tfjob_chief_spec, tfjob_worker_spec)\n\n"],"image":"python:3.7"}'
+          Dict[str, str])])\n    return output(tfjob_chief_spec, tfjob_worker_spec)\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -962,7 +962,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: convert-inference-service-to-artifact
       params:
@@ -987,7 +987,7 @@ spec:
           kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef
           convert_inference_service_to_artifact(inferenceservice_yaml: Dict[str, str],
           inferenceservice_artifact: Output[Artifact]):\n    import json\n    with
-          open(inferenceservice_artifact.path, ''w'') as f:\n        f.write(json.dumps(inferenceservice_yaml))\n\n"],"image":"python:3.7"}'
+          open(inferenceservice_artifact.path, ''w'') as f:\n        f.write(json.dumps(inferenceservice_yaml))\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -1107,7 +1107,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: create-serving-task
       params:
@@ -1138,7 +1138,7 @@ spec:
           {\n            \"sidecar.istio.io/inject\": \"false\"\n          }\n        },\n        \"spec\":{\n          \"predictor\":{\n            \"tensorflow\":
           {\n              \"storageUri\": \"pvc://{}/\".format(model_volume_name)\n            }\n          }\n        }\n    }\n\n    output
           = NamedTuple(''Outputs'', [(''inferenceservice_yaml'', Dict[str, str])])\n    return
-          output(inference_service)\n\n"],"image":"python:3.7"}'
+          output(inference_service)\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -1277,7 +1277,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: serving-launcher
       params:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline_ir.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline_ir.yaml
index e215cccabe10..be0bb9bd0975 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline_ir.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/mnist_pipeline_ir.yaml
@@ -224,7 +224,7 @@ pipelineSpec:
             \ str])-> NamedTuple('Outputs', [('experiment_spec_str_output', str)]):\n\
             \    import json\n    output = NamedTuple('Outputs', [('experiment_spec_str_output',\
             \ str)])\n    return output(json.dumps(experiment_spec_json))\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-convert-inference-service-to-artifact:
         container:
           args:
@@ -253,7 +253,7 @@ pipelineSpec:
             \ Dict[str, str], inferenceservice_artifact: Output[Artifact]):\n    import\
             \ json\n    with open(inferenceservice_artifact.path, 'w') as f:\n     \
             \   f.write(json.dumps(inferenceservice_yaml))\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-convert-katib-results:
         container:
           args:
@@ -289,7 +289,7 @@ pipelineSpec:
             batch_size\":\n            best_hps.append(\"--tf-batch-size=\" + pa[\"\
             value\"])\n    print(\"Best Hyperparameters: {}\".format(best_hps))\n  \
             \  return \" \".join(best_hps)\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-create-dataset:
         container:
           args:
@@ -409,7 +409,7 @@ pipelineSpec:
             \ = ApiClient().sanitize_for_serialization(experiment_spec)\n    output\
             \ = NamedTuple('Outputs', [('experiment_spec_json', Dict[str, str])])\n\
             \    return output(experiment_spec_json)\n\n"
-          image: python:3.8
+          image: python:3.9
       exec-create-serving-task:
         container:
           args:
@@ -446,7 +446,7 @@ pipelineSpec:
             .format(model_volume_name)\n            }\n          }\n        }\n    }\n\
             \n    output = NamedTuple('Outputs', [('inferenceservice_yaml', Dict[str,\
             \ str])])\n    return output(inference_service)\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-create-tfjob-task:
         container:
           args:
@@ -513,7 +513,7 @@ pipelineSpec:
             \          ],\n            }\n        }\n    }\n\n    output = NamedTuple('Outputs',\
             \ [('chief_spec', Dict[str, str]), ('worker_spec', Dict[str, str])])\n \
             \   return output(tfjob_chief_spec, tfjob_worker_spec)\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-serving-launcher:
         container:
           args:
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop.yaml
index b37660ec8d23..877b86d5cb61 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop.yaml
@@ -36,7 +36,7 @@ spec:
           kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef
           flip_coin_op() -\u003e str:\n    \"\"\"Flip a coin and output heads or tails
           randomly.\"\"\"\n    import random\n    result = random.choice([''heads'',
-          ''tails''])\n    print(result)\n    return result\n\n"],"image":"python:3.7"}'
+          ''tails''])\n    print(result)\n    return result\n\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -156,7 +156,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: for-loop-2-pipelineloop
       params:
@@ -228,7 +228,7 @@ spec:
                   -d)\nprintf \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\"\npython3
                   -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
                   kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import
-                  *\n\ndef print_op(message: str):\n    \"\"\"Print a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.7"}'
+                  *\n\ndef print_op(message: str):\n    \"\"\"Print a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.9"}'
               - name: iteration-index
                 value: ""
               - name: kubernetes-config
@@ -345,7 +345,7 @@ spec:
                       - configMapRef:
                           name: metadata-grpc-configmap
                           optional: true
-                      image: python:3.7
+                      image: python:3.9
                       name: user-main
               when:
               - input: $(tasks.condition-4-dag-driver.results.condition)
@@ -424,7 +424,7 @@ spec:
                   -d)\nprintf \"%s\" \"$0\" \u003e \"$program_path/ephemeral_component.py\"\npython3
                   -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\"\n","\nimport
                   kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import
-                  *\n\ndef print_op(message: str):\n    \"\"\"Print a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.7"}'
+                  *\n\ndef print_op(message: str):\n    \"\"\"Print a message.\"\"\"\n    print(message)\n\n"],"image":"python:3.9"}'
               - name: iteration-index
                 value: ""
               - name: kubernetes-config
@@ -541,7 +541,7 @@ spec:
                       - configMapRef:
                           name: metadata-grpc-configmap
                           optional: true
-                      image: python:3.7
+                      image: python:3.9
                       name: user-main
               when:
               - input: $(tasks.condition-5-dag-driver.results.condition)
@@ -621,7 +621,7 @@ spec:
                   *\n\ndef get_random_int_op(minimum: int, maximum: int) -\u003e int:\n    \"\"\"Generate
                   a random number between minimum and maximum (inclusive).\"\"\"\n    import
                   random\n    result = random.randint(minimum, maximum)\n    print(result)\n    return
-                  result\n\n"],"image":"python:3.7"}'
+                  result\n\n"],"image":"python:3.9"}'
               - name: iteration-index
                 value: ""
               - name: kubernetes-config
@@ -741,7 +741,7 @@ spec:
                       - configMapRef:
                           name: metadata-grpc-configmap
                           optional: true
-                      image: python:3.7
+                      image: python:3.9
                       name: user-main
               when:
               - input: $(tasks.condition-3-dag-driver.results.condition)
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop_ir.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop_ir.yaml
index 5dad49057b9d..94a4b33a4785 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop_ir.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/nestedloop_ir.yaml
@@ -204,7 +204,7 @@ pipelineSpec:
             \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
             \ or tails randomly.\"\"\"\n    import random\n    result = random.choice(['heads',\
             \ 'tails'])\n    print(result)\n    return result\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-get-random-int-op:
         container:
           args:
@@ -233,7 +233,7 @@ pipelineSpec:
             \"\"Generate a random number between minimum and maximum (inclusive).\"\"\
             \"\n    import random\n    result = random.randint(minimum, maximum)\n \
             \   print(result)\n    return result\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-print-op:
         container:
           args:
@@ -260,7 +260,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_op(message: str):\n    \"\"\"Print a message.\"\"\"\n \
             \   print(message)\n\n"
-          image: python:3.7
+          image: python:3.9
       exec-print-op-2:
         container:
           args:
@@ -287,7 +287,7 @@ pipelineSpec:
           - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
             \ *\n\ndef print_op(message: str):\n    \"\"\"Print a message.\"\"\"\n \
             \   print(message)\n\n"
-          image: python:3.7
+          image: python:3.9
   pipelineInfo:
     description: Shows how to use dsl.Condition(), dsl.ParallelFor, and dsl.ExitHandler().
     name: tutorial-control-flows
diff --git a/backend/src/v2/compiler/tektoncompiler/testdata/pod_metadata.yaml b/backend/src/v2/compiler/tektoncompiler/testdata/pod_metadata.yaml
index 58cf1d201157..1dfeb2012eac 100644
--- a/backend/src/v2/compiler/tektoncompiler/testdata/pod_metadata.yaml
+++ b/backend/src/v2/compiler/tektoncompiler/testdata/pod_metadata.yaml
@@ -31,7 +31,7 @@ spec:
           hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser
           = argparse.ArgumentParser(prog=''Hello world'', description='''')\n_parser.add_argument(\"--text\",
           dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
-          = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.7"}'
+          = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"],"image":"python:3.9"}'
       - name: iteration-index
         value: ""
       - name: kubernetes-config
@@ -137,7 +137,7 @@ spec:
               - configMapRef:
                   name: metadata-grpc-configmap
                   optional: true
-              image: python:3.7
+              image: python:3.9
               name: user-main
     - name: root-system-dag-driver
       params:
diff --git a/backend/src/v2/compiler/testdata/component_used_twice.json b/backend/src/v2/compiler/testdata/component_used_twice.json
index 6773a1a85040..3fa73594297c 100644
--- a/backend/src/v2/compiler/testdata/component_used_twice.json
+++ b/backend/src/v2/compiler/testdata/component_used_twice.json
@@ -23,7 +23,7 @@
               "program_path=$(mktemp)\nprintf \"%s\" \"$0\" > \"$program_path\"\npython3 -u \"$program_path\" \"$@\"\n",
               "def hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser = argparse.ArgumentParser(prog='Hello world', description='')\n_parser.add_argument(\"--text\", dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"
             ],
-            "image": "python:3.7"
+            "image": "python:3.9"
           }
         }
       }
diff --git a/backend/src/v2/compiler/testdata/create_mount_delete_dynamic_pvc.json b/backend/src/v2/compiler/testdata/create_mount_delete_dynamic_pvc.json
index b4f3b5dc1f42..99b7a7c5db54 100644
--- a/backend/src/v2/compiler/testdata/create_mount_delete_dynamic_pvc.json
+++ b/backend/src/v2/compiler/testdata/create_mount_delete_dynamic_pvc.json
@@ -73,7 +73,7 @@
               "program_path=$(mktemp -d) printf \"%s\" \"$0\" > \"$program_path/ephemeral_component.py\" python3 -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\" ",
               "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef comp():\n    pass\n\n"
             ],
-            "image": "python:3.7"
+            "image": "python:3.9"
           }
         },
         "exec-comp-2": {
@@ -88,7 +88,7 @@
               "program_path=$(mktemp -d) printf \"%s\" \"$0\" > \"$program_path/ephemeral_component.py\" python3 -m kfp.components.executor_main                         --component_module_path                         \"$program_path/ephemeral_component.py\"                         \"$@\" ",
               "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import *\n\ndef comp():\n    pass\n\n"
             ],
-            "image": "python:3.7"
+            "image": "python:3.9"
           }
         },
         "exec-createpvc": {
diff --git a/backend/src/v2/compiler/testdata/hello_world.json b/backend/src/v2/compiler/testdata/hello_world.json
index 0f45d03aaad1..5e41e48315c4 100644
--- a/backend/src/v2/compiler/testdata/hello_world.json
+++ b/backend/src/v2/compiler/testdata/hello_world.json
@@ -26,7 +26,7 @@
               "program_path=$(mktemp)\nprintf \"%s\" \"$0\" > \"$program_path\"\npython3 -u \"$program_path\" \"$@\"\n",
               "def hello_world(text):\n    print(text)\n    return text\n\nimport argparse\n_parser = argparse.ArgumentParser(prog='Hello world', description='')\n_parser.add_argument(\"--text\", dest=\"text\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\n_outputs = hello_world(**_parsed_args)\n"
             ],
-            "image": "python:3.7"
+            "image": "python:3.9"
           }
         }
       }
diff --git a/backend/src/v2/driver/driver_test.go b/backend/src/v2/driver/driver_test.go
index be64723ccfb5..130291f3cac7 100644
--- a/backend/src/v2/driver/driver_test.go
+++ b/backend/src/v2/driver/driver_test.go
@@ -50,7 +50,7 @@ func Test_initPodSpecPatch_acceleratorConfig(t *testing.T) {
 			"Valid - nvidia.com/gpu",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
@@ -89,7 +89,7 @@ func Test_initPodSpecPatch_acceleratorConfig(t *testing.T) {
 			"Valid - amd.com/gpu",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
@@ -128,7 +128,7 @@ func Test_initPodSpecPatch_acceleratorConfig(t *testing.T) {
 			"Valid - cloud-tpus.google.com/v3",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
@@ -167,7 +167,7 @@ func Test_initPodSpecPatch_acceleratorConfig(t *testing.T) {
 			"Valid - cloud-tpus.google.com/v2",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
@@ -206,7 +206,7 @@ func Test_initPodSpecPatch_acceleratorConfig(t *testing.T) {
 			"Valid - custom string",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
@@ -335,7 +335,7 @@ func Test_initPodSpecPatch_resourceRequests(t *testing.T) {
 			"Valid - with requests",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
@@ -371,7 +371,7 @@ func Test_initPodSpecPatch_resourceRequests(t *testing.T) {
 			"Valid - zero requests",
 			args{
 				&pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec{
-					Image:   "python:3.7",
+					Image:   "python:3.9",
 					Args:    []string{"--function_to_execute", "add"},
 					Command: []string{"sh", "-ec", "python3 -m kfp.components.executor_main"},
 					Resources: &pipelinespec.PipelineDeploymentConfig_PipelineContainerSpec_ResourceSpec{
diff --git a/backend/src/v2/test/Dockerfile b/backend/src/v2/test/Dockerfile
index 7c38ed6c9f74..caf7acc9c6a1 100644
--- a/backend/src/v2/test/Dockerfile
+++ b/backend/src/v2/test/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM python:3.7-slim
+FROM python:3.9-slim
 
 WORKDIR /workdir
 COPY backend/src/v2/test/requirements.txt backend/src/v2/test/
diff --git a/backend/src/v2/test/components/run_sample.yaml b/backend/src/v2/test/components/run_sample.yaml
index d4b4c9b7e973..ceb5f3402084 100644
--- a/backend/src/v2/test/components/run_sample.yaml
+++ b/backend/src/v2/test/components/run_sample.yaml
@@ -24,7 +24,7 @@ inputs:
 - {name: backend_compiler, type: Binary}
 implementation:
   container:
-    image: python:3.7-alpine
+    image: python:3.9-alpine
     command:
     - sh
     - -exc
diff --git a/backend/test/resources/v2-hello-world.yaml b/backend/test/resources/v2-hello-world.yaml
index c20d47c0650b..203c205f26ba 100644
--- a/backend/test/resources/v2-hello-world.yaml
+++ b/backend/test/resources/v2-hello-world.yaml
@@ -30,7 +30,7 @@ deploymentSpec:
           _parsed_args = vars(_parser.parse_args())
 
           _outputs = hello_world(**_parsed_args)
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: hello-world
 root:
diff --git a/backend/update_requirements.sh b/backend/update_requirements.sh
index 920940e90928..93c811f474d9 100755
--- a/backend/update_requirements.sh
+++ b/backend/update_requirements.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
 
 # This image should be in sync with Dockerfile.
-IMAGE="python:3.7"
+IMAGE="python:3.9"
 ../hack/update-requirements.sh $IMAGE requirements.txt
diff --git a/components/google-cloud/google_cloud_pipeline_components/__init__.py b/components/google-cloud/google_cloud_pipeline_components/__init__.py
index 4af23fae73e1..19e1c51ec3fa 100644
--- a/components/google-cloud/google_cloud_pipeline_components/__init__.py
+++ b/components/google-cloud/google_cloud_pipeline_components/__init__.py
@@ -20,9 +20,9 @@
 if sys.version_info < (3, 9):
   warnings.warn(
       (
-          ' Google Cloud Pipeline Components will drop support for Python 3.8'
-          ' on Oct 1, 2024. To use new versions of the GCPC SDK after that'
-          ' date, you will need to upgrade to Python >= 3.9. See'
+          ' Google Cloud Pipeline Components will drop support for Python 3.9'
+          ' on Oct 1, 2025. To use new versions of the GCPC SDK after that'
+          ' date, you will need to upgrade to Python >= 3.10. See'
           ' https://devguide.python.org/versions/ for more details.'
       ),
       FutureWarning,
diff --git a/kubernetes_platform/python/docs/.readthedocs.yml b/kubernetes_platform/python/docs/.readthedocs.yml
index 290660f2e76d..161aca4a9efc 100644
--- a/kubernetes_platform/python/docs/.readthedocs.yml
+++ b/kubernetes_platform/python/docs/.readthedocs.yml
@@ -5,7 +5,7 @@ sphinx:
 build:
   os: ubuntu-22.04
   tools:
-    python: "3.8"
+    python: "3.9"
 python:
   install:
     - requirements: kubernetes_platform/python/docs/requirements.txt
diff --git a/kubernetes_platform/python/setup.py b/kubernetes_platform/python/setup.py
index 6d3d1d191513..b8b3781e44ba 100644
--- a/kubernetes_platform/python/setup.py
+++ b/kubernetes_platform/python/setup.py
@@ -76,7 +76,7 @@ def read_readme() -> str:
             'https://github.com/kubeflow/pipelines/tree/master/kubernetes_platform/python',
     },
     packages=setuptools.find_namespace_packages(include=['kfp.*']),
-    python_requires='>=3.8.0,<3.13.0',
+    python_requires='>=3.9.0,<3.13.0',
     install_requires=REQUIREMENTS,
     include_package_data=True,
     extras_require={
diff --git a/kubernetes_platform/python/test/snapshot/data/config_map_as_env.yaml b/kubernetes_platform/python/test/snapshot/data/config_map_as_env.yaml
index 0f3583e55149..36d242bac9a6 100644
--- a/kubernetes_platform/python/test/snapshot/data/config_map_as_env.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/config_map_as_env.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/config_map_as_vol.yaml b/kubernetes_platform/python/test/snapshot/data/config_map_as_vol.yaml
index 2d165389d54f..a68f3ce2db43 100644
--- a/kubernetes_platform/python/test/snapshot/data/config_map_as_vol.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/config_map_as_vol.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/create_mount_delete_dynamic_pvc.yaml b/kubernetes_platform/python/test/snapshot/data/create_mount_delete_dynamic_pvc.yaml
index 2aa908ac6c69..124430a41d30 100644
--- a/kubernetes_platform/python/test/snapshot/data/create_mount_delete_dynamic_pvc.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/create_mount_delete_dynamic_pvc.yaml
@@ -113,7 +113,7 @@ deploymentSpec:
           \ *\n\ndef consumer() -> str:\n    with open('/data/file.txt', 'r') as file:\n\
           \        content = file.read()\n    print(content)\n    return content\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-createpvc:
       container:
         image: argostub/createpvc
@@ -150,7 +150,7 @@ deploymentSpec:
           \        file.write('Hello world')\n    with open('/data/file.txt', 'r')\
           \ as file:\n        content = file.read()\n    print(content)\n    return\
           \ content\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc.yaml b/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc.yaml
index 0b68d5a0cb55..d42aadc2c9a7 100644
--- a/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc.yaml
@@ -101,7 +101,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-createpvc:
       container:
         image: argostub/createpvc
diff --git a/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc_from_task_output.yaml b/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc_from_task_output.yaml
index 44a9704303a4..1348100c461c 100644
--- a/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc_from_task_output.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/create_mount_delete_existing_pvc_from_task_output.yaml
@@ -107,7 +107,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-createpvc:
       container:
         image: argostub/createpvc
@@ -141,7 +141,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef get_pvc_name() -> str:\n    return 'static-pvc-name'\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/field_path_as_env.yaml b/kubernetes_platform/python/test/snapshot/data/field_path_as_env.yaml
index 7630f9f62911..c7590fe8bc8d 100644
--- a/kubernetes_platform/python/test/snapshot/data/field_path_as_env.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/field_path_as_env.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/general_ephemeral_volume.yaml b/kubernetes_platform/python/test/snapshot/data/general_ephemeral_volume.yaml
index 3dd18473cb8e..87402a2f2f90 100644
--- a/kubernetes_platform/python/test/snapshot/data/general_ephemeral_volume.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/general_ephemeral_volume.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/image_pull_secrets.yaml b/kubernetes_platform/python/test/snapshot/data/image_pull_secrets.yaml
index 60a385b55188..d399211f4cff 100644
--- a/kubernetes_platform/python/test/snapshot/data/image_pull_secrets.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/image_pull_secrets.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/node_selector.yaml b/kubernetes_platform/python/test/snapshot/data/node_selector.yaml
index e1194a945e69..addc0db0d91f 100644
--- a/kubernetes_platform/python/test/snapshot/data/node_selector.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/node_selector.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/secret_as_env.yaml b/kubernetes_platform/python/test/snapshot/data/secret_as_env.yaml
index c24a65df0cdb..85aacaec96bf 100644
--- a/kubernetes_platform/python/test/snapshot/data/secret_as_env.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/secret_as_env.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/secret_as_vol.yaml b/kubernetes_platform/python/test/snapshot/data/secret_as_vol.yaml
index 181077500bc8..98f8011a4e68 100644
--- a/kubernetes_platform/python/test/snapshot/data/secret_as_vol.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/secret_as_vol.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/timeout.yaml b/kubernetes_platform/python/test/snapshot/data/timeout.yaml
index d2afd3531928..295ace7b58af 100644
--- a/kubernetes_platform/python/test/snapshot/data/timeout.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/timeout.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/kubernetes_platform/python/test/snapshot/data/toleration.yaml b/kubernetes_platform/python/test/snapshot/data/toleration.yaml
index 1ac6253c0c8c..843ab9c9cc9f 100644
--- a/kubernetes_platform/python/test/snapshot/data/toleration.yaml
+++ b/kubernetes_platform/python/test/snapshot/data/toleration.yaml
@@ -32,7 +32,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef comp():\n    pass\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/deployment.yaml b/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/deployment.yaml
index 99dd9e21c61a..636f7523f6bd 100644
--- a/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/deployment.yaml
+++ b/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/deployment.yaml
@@ -11,7 +11,7 @@ spec:
     spec:
       containers:
       - name: profile-controller
-        image: python:3.7
+        image: python:3.9
         command: ["python", "/hooks/sync.py"]
         envFrom:
         - configMapRef:
diff --git a/sdk/python/kfp/__init__.py b/sdk/python/kfp/__init__.py
index 9c4a79e80ca8..00663907036e 100644
--- a/sdk/python/kfp/__init__.py
+++ b/sdk/python/kfp/__init__.py
@@ -23,7 +23,7 @@
 
 if sys.version_info < (3, 9):
     warnings.warn(
-        ('KFP will drop support for Python 3.8 on Oct 1, 2024. To use new versions of the KFP SDK after that date, you will need to upgrade to Python >= 3.9. See https://devguide.python.org/versions/ for more details.'
+        ('KFP will drop support for Python 3.9 on Oct 1, 2025. To use new versions of the KFP SDK after that date, you will need to upgrade to Python >= 3.10. See https://devguide.python.org/versions/ for more details.'
         ),
         FutureWarning,
         stacklevel=2,
diff --git a/sdk/python/kfp/cli/compile_test.py b/sdk/python/kfp/cli/compile_test.py
index cf7169863eec..c11d43e2a4e1 100644
--- a/sdk/python/kfp/cli/compile_test.py
+++ b/sdk/python/kfp/cli/compile_test.py
@@ -29,7 +29,7 @@ def my_comp():
         @dsl.container_component
         def my_container_comp():
             return dsl.ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=['echo', 'hello world'],
                 args=[],
             )
@@ -55,7 +55,7 @@ def my_comp():
         @dsl.container_component
         def my_container_comp():
             return dsl.ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=['echo', 'hello world'],
                 args=[],
             )
diff --git a/sdk/python/kfp/cli/component_test.py b/sdk/python/kfp/cli/component_test.py
index 7a40ac73822c..d6240efdbe11 100644
--- a/sdk/python/kfp/cli/component_test.py
+++ b/sdk/python/kfp/cli/component_test.py
@@ -466,7 +466,7 @@ def test_docker_file_is_created_correctly(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.8
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY runtime-requirements.txt runtime-requirements.txt
@@ -495,7 +495,7 @@ def test_docker_file_is_created_correctly_with_one_url(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.8
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY runtime-requirements.txt runtime-requirements.txt
@@ -526,7 +526,7 @@ def test_docker_file_is_created_correctly_with_two_urls(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.8
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY runtime-requirements.txt runtime-requirements.txt
@@ -569,7 +569,7 @@ def test_existing_dockerfile_can_be_overwritten(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.8
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY runtime-requirements.txt runtime-requirements.txt
@@ -608,7 +608,7 @@ def test_dockerfile_can_contain_custom_kfp_package(self):
         file_start = textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.8
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY runtime-requirements.txt runtime-requirements.txt
@@ -637,7 +637,7 @@ def test_docker_file_is_created_one_trusted_host(self):
             textwrap.dedent('''\
                     # Generated by KFP.
     
-                    FROM python:3.8
+                    FROM python:3.9
     
                     WORKDIR /usr/local/src/kfp/components
                     COPY runtime-requirements.txt runtime-requirements.txt
@@ -667,7 +667,7 @@ def test_docker_file_is_created_two_trusted_host(self):
             textwrap.dedent('''\
                     # Generated by KFP.
     
-                    FROM python:3.8
+                    FROM python:3.9
     
                     WORKDIR /usr/local/src/kfp/components
                     COPY runtime-requirements.txt runtime-requirements.txt
diff --git a/sdk/python/kfp/compiler/compiler_test.py b/sdk/python/kfp/compiler/compiler_test.py
index d417d9eec199..7f0cfd4b98a3 100644
--- a/sdk/python/kfp/compiler/compiler_test.py
+++ b/sdk/python/kfp/compiler/compiler_test.py
@@ -696,7 +696,7 @@ def test_use_task_final_status_in_non_exit_op_yaml(self):
 - {name: message, type: PipelineTaskFinalStatus}
 implementation:
   container:
-    image: python:3.7
+    image: python:3.9
     command:
     - echo
     - {inputValue: message}
@@ -1172,7 +1172,7 @@ def test_compile_container_component_simple(self):
         def hello_world_container() -> dsl.ContainerSpec:
             """Hello world component."""
             return dsl.ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=['echo', 'hello world'],
                 args=[],
             )
@@ -1195,7 +1195,7 @@ def test_compile_container_with_simple_io(self):
         @dsl.container_component
         def container_simple_io(text: str, output_path: dsl.OutputPath(str)):
             return dsl.ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=['my_program', text],
                 args=['--output_path', output_path])
 
@@ -2243,7 +2243,7 @@ def my_component(string: str, model: bool) -> str:
         def my_container_component(text: str, output_path: OutputPath(str)):
             """component description."""
             return ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=['my_program', text],
                 args=['--output_path', output_path])
 
diff --git a/sdk/python/kfp/components/load_yaml_utilities_test.py b/sdk/python/kfp/components/load_yaml_utilities_test.py
index 55ba29cf575c..8130bb2e851a 100644
--- a/sdk/python/kfp/components/load_yaml_utilities_test.py
+++ b/sdk/python/kfp/components/load_yaml_utilities_test.py
@@ -111,7 +111,7 @@ def test_load_component_from_file(self):
             component.component_spec.implementation.container.image, 'alpine')
 
     def test_load_component_from_url(self):
-        component_url = 'https://raw.githubusercontent.com/kubeflow/pipelines/7b49eadf621a9054e1f1315c86f95fb8cf8c17c3/sdk/python/kfp/compiler/test_data/components/identity.yaml'
+        component_url = 'https://raw.githubusercontent.com/kubeflow/pipelines/5d0ace427d55ee04da028cb19613018aed0b2042/sdk/python/test_data/components/identity.yaml'
         component = components.load_component_from_url(component_url)
 
         self.assertEqual(component.component_spec.name, 'identity')
@@ -121,7 +121,7 @@ def test_load_component_from_url(self):
         self.assertEqual(component.name, 'identity')
         self.assertEqual(
             component.component_spec.implementation.container.image,
-            'python:3.7')
+            'python:3.9')
 
 
 if __name__ == '__main__':
diff --git a/sdk/python/kfp/deprecated/cli/components_test.py b/sdk/python/kfp/deprecated/cli/components_test.py
index 5eda0cc43ef5..6d2e6cea0e3e 100644
--- a/sdk/python/kfp/deprecated/cli/components_test.py
+++ b/sdk/python/kfp/deprecated/cli/components_test.py
@@ -404,7 +404,7 @@ def testDockerfileIsCreatedCorrectly(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.7
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY requirements.txt requirements.txt
@@ -447,7 +447,7 @@ def testExistingDockerfileCanBeOverwritten(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.7
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY requirements.txt requirements.txt
@@ -477,7 +477,7 @@ def testDockerfileCanContainCustomKFPPackage(self):
             textwrap.dedent('''\
                 # Generated by KFP.
 
-                FROM python:3.7
+                FROM python:3.9
 
                 WORKDIR /usr/local/src/kfp/components
                 COPY requirements.txt requirements.txt
diff --git a/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline.yaml b/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline.yaml
index 57809640aa8f..b85db0a0a3a4 100644
--- a/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline.yaml
+++ b/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline.yaml
@@ -101,7 +101,7 @@ spec:
       - name: ENABLE_CACHING
         valueFrom:
           fieldRef: {fieldPath: 'metadata.labels[''pipelines.kubeflow.org/enable_caching'']'}
-      - {name: KFP_V2_IMAGE, value: 'python:3.7'}
+      - {name: KFP_V2_IMAGE, value: 'python:3.9'}
       - {name: KFP_V2_RUNTIME_INFO, value: '{"inputParameters": {"some_int": {"type":
           "NUMBER_INTEGER"}, "uri": {"type": "STRING"}}, "inputArtifacts": {}, "outputParameters":
           {"output_parameter_one": {"type": "NUMBER_INTEGER", "path": "/tmp/outputs/output_parameter_one/data"}},
@@ -109,7 +109,7 @@ spec:
           "instanceSchema": "", "schemaVersion": "0.0.1", "metadataPath": "/tmp/outputs/output_dataset_one/data"}}}'}
       envFrom:
       - configMapRef: {name: metadata-grpc-configmap, optional: true}
-      image: python:3.7
+      image: python:3.9
       volumeMounts:
       - {mountPath: /kfp-launcher, name: kfp-launcher}
     inputs:
@@ -208,7 +208,7 @@ spec:
       - name: ENABLE_CACHING
         valueFrom:
           fieldRef: {fieldPath: 'metadata.labels[''pipelines.kubeflow.org/enable_caching'']'}
-      - {name: KFP_V2_IMAGE, value: 'python:3.7'}
+      - {name: KFP_V2_IMAGE, value: 'python:3.9'}
       - {name: KFP_V2_RUNTIME_INFO, value: '{"inputParameters": {"num_steps": {"type":
           "NUMBER_INTEGER"}}, "inputArtifacts": {"dataset": {"metadataPath": "/tmp/inputs/dataset/data",
           "schemaTitle": "system.Dataset", "instanceSchema": "", "schemaVersion":
@@ -217,7 +217,7 @@ spec:
           "/tmp/outputs/model/data"}}}'}
       envFrom:
       - configMapRef: {name: metadata-grpc-configmap, optional: true}
-      image: python:3.7
+      image: python:3.9
       volumeMounts:
       - {mountPath: /kfp-launcher, name: kfp-launcher}
     inputs:
diff --git a/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline_with_custom_launcher.yaml b/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline_with_custom_launcher.yaml
index b8fd8185806c..94195b292a3c 100644
--- a/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline_with_custom_launcher.yaml
+++ b/sdk/python/kfp/deprecated/compiler/testdata/v2_compatible_two_step_pipeline_with_custom_launcher.yaml
@@ -101,7 +101,7 @@ spec:
       - name: ENABLE_CACHING
         valueFrom:
           fieldRef: {fieldPath: 'metadata.labels[''pipelines.kubeflow.org/enable_caching'']'}
-      - {name: KFP_V2_IMAGE, value: 'python:3.7'}
+      - {name: KFP_V2_IMAGE, value: 'python:3.9'}
       - {name: KFP_V2_RUNTIME_INFO, value: '{"inputParameters": {"some_int": {"type":
           "NUMBER_INTEGER"}, "uri": {"type": "STRING"}}, "inputArtifacts": {}, "outputParameters":
           {"output_parameter_one": {"type": "NUMBER_INTEGER", "path": "/tmp/outputs/output_parameter_one/data"}},
@@ -109,7 +109,7 @@ spec:
           "instanceSchema": "", "schemaVersion": "0.0.1", "metadataPath": "/tmp/outputs/output_dataset_one/data"}}}'}
       envFrom:
       - configMapRef: {name: metadata-grpc-configmap, optional: true}
-      image: python:3.7
+      image: python:3.9
       volumeMounts:
       - {mountPath: /kfp-launcher, name: kfp-launcher}
     inputs:
@@ -208,7 +208,7 @@ spec:
       - name: ENABLE_CACHING
         valueFrom:
           fieldRef: {fieldPath: 'metadata.labels[''pipelines.kubeflow.org/enable_caching'']'}
-      - {name: KFP_V2_IMAGE, value: 'python:3.7'}
+      - {name: KFP_V2_IMAGE, value: 'python:3.9'}
       - {name: KFP_V2_RUNTIME_INFO, value: '{"inputParameters": {"num_steps": {"type":
           "NUMBER_INTEGER"}}, "inputArtifacts": {"dataset": {"metadataPath": "/tmp/inputs/dataset/data",
           "schemaTitle": "system.Dataset", "instanceSchema": "", "schemaVersion":
@@ -217,7 +217,7 @@ spec:
           "/tmp/outputs/model/data"}}}'}
       envFrom:
       - configMapRef: {name: metadata-grpc-configmap, optional: true}
-      image: python:3.7
+      image: python:3.9
       volumeMounts:
       - {mountPath: /kfp-launcher, name: kfp-launcher}
     inputs:
diff --git a/sdk/python/kfp/deprecated/components/_python_op.py b/sdk/python/kfp/deprecated/components/_python_op.py
index 423b577148a5..d24924e0cac0 100644
--- a/sdk/python/kfp/deprecated/components/_python_op.py
+++ b/sdk/python/kfp/deprecated/components/_python_op.py
@@ -152,7 +152,7 @@ def make_parent_dirs_and_return_path(file_path: str):
     return make_parent_dirs_and_return_path
 
 
-default_base_image_or_builder = 'python:3.7'
+default_base_image_or_builder = 'python:3.9'
 
 
 def _python_function_name_to_component_name(name):
@@ -1026,7 +1026,7 @@ def add(a: float, b: float) -> float:
             # add_op is a task factory function that creates a task object when given arguments
             add_op = create_component_from_func(
                 func=add,
-                base_image='python:3.7', # Optional
+                base_image='python:3.9', # Optional
                 output_component_file='add.component.yaml', # Optional
                 packages_to_install=['pandas==0.24'], # Optional
             )
diff --git a/sdk/python/kfp/deprecated/containers_tests/test_build_image_api.py b/sdk/python/kfp/deprecated/containers_tests/test_build_image_api.py
index cffb4d2b7838..bdfb9d3e2e20 100644
--- a/sdk/python/kfp/deprecated/containers_tests/test_build_image_api.py
+++ b/sdk/python/kfp/deprecated/containers_tests/test_build_image_api.py
@@ -52,7 +52,7 @@ class BuildImageApiTests(unittest.TestCase):
 
     def test_build_image_from_working_dir(self):
         expected_dockerfile_text_re = '''
-FROM python:3.6.5
+FROM python:3.9
 WORKDIR /.*
 COPY requirements.txt .
 RUN python3 -m pip install -r requirements.txt
@@ -96,7 +96,7 @@ def file_paths_check(file_paths):
                                        file_paths_check)
             result = build_image_from_working_dir(
                 working_dir=context_dir,
-                base_image='python:3.6.5',
+                base_image='python:3.9',
                 builder=builder)
 
     def test_image_cache(self):
@@ -110,7 +110,7 @@ def test_image_cache(self):
                 py_content='py1', sh_content='sh1') as context_dir:
             build_image_from_working_dir(
                 working_dir=context_dir,
-                base_image='python:3.6.5',
+                base_image='python:3.9',
                 builder=builder)
         self.assertEqual(builder.invocations_count, 1)
 
@@ -119,7 +119,7 @@ def test_image_cache(self):
                 py_content='py1', sh_content='sh2') as context_dir:
             build_image_from_working_dir(
                 working_dir=context_dir,
-                base_image='python:3.6.5',
+                base_image='python:3.9',
                 builder=builder)
         self.assertEqual(builder.invocations_count, 1)
 
@@ -128,7 +128,7 @@ def test_image_cache(self):
                 py_content='py2', sh_content='sh1') as context_dir:
             build_image_from_working_dir(
                 working_dir=context_dir,
-                base_image='python:3.6.5',
+                base_image='python:3.9',
                 builder=builder)
         self.assertEqual(builder.invocations_count, 2)
 
diff --git a/sdk/python/kfp/deprecated/dsl/_container_op_test.py b/sdk/python/kfp/deprecated/dsl/_container_op_test.py
index a712f6987ecd..00f2e9d88036 100644
--- a/sdk/python/kfp/deprecated/dsl/_container_op_test.py
+++ b/sdk/python/kfp/deprecated/dsl/_container_op_test.py
@@ -38,7 +38,7 @@
 class ContainerOpTest(unittest.TestCase):
 
     def test_chained_call_resource_setter(self):
-        task = _container_op.ContainerOp(name='test_task', image='python:3.7')
+        task = _container_op.ContainerOp(name='test_task', image='python:3.9')
         task.container_spec = _PipelineContainerSpec()
         (task.set_cpu_limit('1').set_memory_limit(
             '1G').add_node_selector_constraint(
diff --git a/sdk/python/kfp/dsl/component_factory.py b/sdk/python/kfp/dsl/component_factory.py
index 2f14aded2c47..c649424bac3a 100644
--- a/sdk/python/kfp/dsl/component_factory.py
+++ b/sdk/python/kfp/dsl/component_factory.py
@@ -36,7 +36,7 @@
 from kfp.dsl.types import type_annotations
 from kfp.dsl.types import type_utils
 
-_DEFAULT_BASE_IMAGE = 'python:3.8'
+_DEFAULT_BASE_IMAGE = 'python:3.9'
 SINGLE_OUTPUT_NAME = 'Output'
 
 
@@ -554,7 +554,7 @@ def create_component_from_func(
     if base_image is None:
         base_image = _DEFAULT_BASE_IMAGE
         warnings.warn(
-            ("The default base_image used by the @dsl.component decorator will switch from 'python:3.8' to 'python:3.9' on Oct 1, 2024. To ensure your existing components work with versions of the KFP SDK released after that date, you should provide an explicit base_image argument and ensure your component works as intended on Python 3.9."
+            ("The default base_image used by the @dsl.component decorator will switch from 'python:3.9' to 'python:3.10' on Oct 1, 2025. To ensure your existing components work with versions of the KFP SDK released after that date, you should provide an explicit base_image argument and ensure your component works as intended on Python 3.10."
             ),
             FutureWarning,
             stacklevel=2,
diff --git a/sdk/python/kfp/dsl/component_factory_test.py b/sdk/python/kfp/dsl/component_factory_test.py
index 28ebbece2928..281d4ad70f35 100644
--- a/sdk/python/kfp/dsl/component_factory_test.py
+++ b/sdk/python/kfp/dsl/component_factory_test.py
@@ -329,7 +329,7 @@ def test_default_base_image(self):
 
         with self.assertWarnsRegex(
                 FutureWarning,
-                r"The default base_image used by the @dsl\.component decorator will switch from 'python:3\.8' to 'python:3\.9' on Oct 1, 2024\. To ensure your existing components work with versions of the KFP SDK released after that date, you should provide an explicit base_image argument and ensure your component works as intended on Python 3\.9\."
+                r"The default base_image used by the @dsl\.component decorator will switch from 'python:3\.9' to 'python:3\.10' on Oct 1, 2025\. To ensure your existing components work with versions of the KFP SDK released after that date, you should provide an explicit base_image argument and ensure your component works as intended on Python 3\.10\."
         ):
 
             @dsl.component
diff --git a/sdk/python/kfp/dsl/container_component_decorator_test.py b/sdk/python/kfp/dsl/container_component_decorator_test.py
index d49253b1e8f6..b690fd5e3759 100644
--- a/sdk/python/kfp/dsl/container_component_decorator_test.py
+++ b/sdk/python/kfp/dsl/container_component_decorator_test.py
@@ -30,7 +30,7 @@ def test_func_with_no_arg(self):
         def hello_world() -> dsl.ContainerSpec:
             """Hello world component."""
             return dsl.ContainerSpec(
-                image='python3.7',
+                image='python3.9',
                 command=['echo', 'hello world'],
                 args=[],
             )
@@ -47,7 +47,7 @@ def hello_world_io(
             text_output_path: dsl.OutputPath(str)) -> dsl.ContainerSpec:
             """Hello world component with input and output."""
             return dsl.ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=['echo'],
                 args=['--text', text, '--output_path', text_output_path])
 
diff --git a/sdk/python/kfp/dsl/placeholders.py b/sdk/python/kfp/dsl/placeholders.py
index edd22e088542..d8b0dfb9446b 100644
--- a/sdk/python/kfp/dsl/placeholders.py
+++ b/sdk/python/kfp/dsl/placeholders.py
@@ -179,7 +179,7 @@ class ConcatPlaceholder(Placeholder):
         def container_with_concat_placeholder(text1: str, text2: Output[Dataset],
                                               output_path: OutputPath(str)):
             return ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=[
                     'my_program',
                     ConcatPlaceholder(['prefix-', text1, text2.uri])
@@ -227,7 +227,7 @@ def container_with_if_placeholder(output_path: OutputPath(str),
                                           dataset: Output[Dataset],
                                           optional_input: str = 'default'):
             return ContainerSpec(
-                    image='python:3.7',
+                    image='python:3.9',
                     command=[
                         'my_program',
                         IfPresentPlaceholder(
diff --git a/sdk/python/kfp/dsl/placeholders_test.py b/sdk/python/kfp/dsl/placeholders_test.py
index a6310ed5b5b3..c05cb4b0b234 100644
--- a/sdk/python/kfp/dsl/placeholders_test.py
+++ b/sdk/python/kfp/dsl/placeholders_test.py
@@ -514,7 +514,7 @@ def container_with_placeholder_in_fstring(
             text1: str,
         ):
             return dsl.ContainerSpec(
-                image='python:3.7',
+                image='python:3.9',
                 command=[
                     'my_program',
                     f'prefix-{text1}',
@@ -540,7 +540,7 @@ def container_with_placeholder_in_fstring(
                 text2: str,
             ):
                 return dsl.ContainerSpec(
-                    image='python:3.7',
+                    image='python:3.9',
                     command=[
                         'my_program',
                         f'another-prefix-{dsl.ConcatPlaceholder([text1, text2])}',
@@ -557,7 +557,7 @@ def container_with_placeholder_in_fstring(
                 text2: str,
             ):
                 return dsl.ContainerSpec(
-                    image='python:3.7',
+                    image='python:3.9',
                     command=[
                         'echo',
                         f"another-prefix-{dsl.IfPresentPlaceholder(input_name='text1', then=['val'])}",
diff --git a/sdk/python/kfp/dsl/structures_test.py b/sdk/python/kfp/dsl/structures_test.py
index 4bdb7bf9a598..29ebc7f16a54 100644
--- a/sdk/python/kfp/dsl/structures_test.py
+++ b/sdk/python/kfp/dsl/structures_test.py
@@ -454,7 +454,7 @@ def test_env(self):
 
     def test_from_container_dict_no_placeholders(self):
         expected_container_spec = structures.ContainerSpecImplementation(
-            image='python:3.7',
+            image='python:3.9',
             command=['sh', '-c', 'dummy'],
             args=['--executor_input', '{{$}}', '--function_to_execute', 'func'],
             env={'ENV1': 'val1'},
@@ -465,7 +465,7 @@ def test_from_container_dict_no_placeholders(self):
                 '--executor_input', '{{$}}', '--function_to_execute', 'func'
             ],
             'command': ['sh', '-c', 'dummy'],
-            'image': 'python:3.7',
+            'image': 'python:3.9',
             'env': {
                 'ENV1': 'val1'
             },
diff --git a/sdk/python/kfp/init_test.py b/sdk/python/kfp/init_test.py
index e5b83183820c..ca2815c21fa5 100644
--- a/sdk/python/kfp/init_test.py
+++ b/sdk/python/kfp/init_test.py
@@ -26,7 +26,7 @@ def test(self):
 
         with self.assertWarnsRegex(
                 FutureWarning,
-                r'KFP will drop support for Python 3\.8 on Oct 1, 2024\. To use new versions of the KFP SDK after that date, you will need to upgrade to Python >= 3\.9\. See https:\/\/devguide\.python\.org\/versions\/ for more details\.'
+                r'KFP will drop support for Python 3.9 on Oct 1, 2025. To use new versions of the KFP SDK after that date, you will need to upgrade to Python >= 3.10. See https://devguide.python.org/versions/ for more details.'
         ):
             # simulate first import from kfp
             importlib.reload(mod)
diff --git a/sdk/python/kfp/local/docker_task_handler_test.py b/sdk/python/kfp/local/docker_task_handler_test.py
index 9bf3e1337fb7..71f8be21361b 100755
--- a/sdk/python/kfp/local/docker_task_handler_test.py
+++ b/sdk/python/kfp/local/docker_task_handler_test.py
@@ -190,7 +190,7 @@ def artifact_maker(x: str, a: Output[Artifact]):
         kwargs = run_mock.call_args[1]
         self.assertEqual(
             kwargs['image'],
-            'python:3.8',
+            'python:3.9',
         )
         self.assertTrue(
             any('def artifact_maker' in c for c in kwargs['command']))
diff --git a/sdk/python/setup.py b/sdk/python/setup.py
index 02439f9b0d75..39619be6577a 100644
--- a/sdk/python/setup.py
+++ b/sdk/python/setup.py
@@ -87,7 +87,6 @@ def read_readme() -> str:
         'Intended Audience :: Science/Research',
         'License :: OSI Approved :: Apache Software License',
         'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
         'Programming Language :: Python :: 3.11',
@@ -98,7 +97,7 @@ def read_readme() -> str:
         'Topic :: Software Development :: Libraries',
         'Topic :: Software Development :: Libraries :: Python Modules',
     ],
-    python_requires='>=3.8.0,<3.13.0',
+    python_requires='>=3.9.0,<3.13.0',
     include_package_data=True,
     entry_points={
         'console_scripts': [
diff --git a/sdk/python/test_data/components/add_numbers.yaml b/sdk/python/test_data/components/add_numbers.yaml
index 3bb751c03f71..197646adec61 100644
--- a/sdk/python/test_data/components/add_numbers.yaml
+++ b/sdk/python/test_data/components/add_numbers.yaml
@@ -47,7 +47,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add_numbers(a: int, b: int) -> int:\n    return a + b\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: add-numbers
 root:
diff --git a/sdk/python/test_data/components/component_with_metadata_fields.yaml b/sdk/python/test_data/components/component_with_metadata_fields.yaml
index d0dd1051ae4f..4547d34d7225 100644
--- a/sdk/python/test_data/components/component_with_metadata_fields.yaml
+++ b/sdk/python/test_data/components/component_with_metadata_fields.yaml
@@ -72,7 +72,7 @@ deploymentSpec:
           \ as f:\n        content_b = f.read()\n\n    concatenated_string = content_a\
           \ + content_b\n    with open(out_dataset.path, 'w') as f:\n        f.write(concatenated_string)\n\
           \n    return concatenated_string\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: dataset-joiner
 root:
diff --git a/sdk/python/test_data/components/component_with_pip_install.yaml b/sdk/python/test_data/components/component_with_pip_install.yaml
index 75d729676143..e6b0fe11513f 100644
--- a/sdk/python/test_data/components/component_with_pip_install.yaml
+++ b/sdk/python/test_data/components/component_with_pip_install.yaml
@@ -35,7 +35,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef component_with_pip_install():\n    import yapf\n    print(dir(yapf))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: component-with-pip-install
 root:
diff --git a/sdk/python/test_data/components/component_with_task_final_status.yaml b/sdk/python/test_data/components/component_with_task_final_status.yaml
index 04f8782bc4fd..2b1fca875f4a 100644
--- a/sdk/python/test_data/components/component_with_task_final_status.yaml
+++ b/sdk/python/test_data/components/component_with_task_final_status.yaml
@@ -40,7 +40,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef exit_comp(status: dsl.PipelineTaskFinalStatus):\n    print(status)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: exit-comp
 root:
diff --git a/sdk/python/test_data/components/concat_message.yaml b/sdk/python/test_data/components/concat_message.yaml
index 2f2e0b73ab05..381a8f22f739 100644
--- a/sdk/python/test_data/components/concat_message.yaml
+++ b/sdk/python/test_data/components/concat_message.yaml
@@ -48,7 +48,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef concat_message(message1: str, message2: str) -> str:\n    return\
           \ message1 + message2\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: concat-message
 root:
diff --git a/sdk/python/test_data/components/container_io.py b/sdk/python/test_data/components/container_io.py
index 1b64bbc0b1b5..294de386d7d8 100644
--- a/sdk/python/test_data/components/container_io.py
+++ b/sdk/python/test_data/components/container_io.py
@@ -19,7 +19,7 @@
 @container_component
 def container_io(text: str, output_path: OutputPath(str)):
     return ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=['my_program', text],
         args=['--output_path', output_path])
 
diff --git a/sdk/python/test_data/components/container_io.yaml b/sdk/python/test_data/components/container_io.yaml
index 1ed70066c3b8..0b7d13d8ac54 100644
--- a/sdk/python/test_data/components/container_io.yaml
+++ b/sdk/python/test_data/components/container_io.yaml
@@ -25,7 +25,7 @@ deploymentSpec:
         command:
         - my_program
         - '{{$.inputs.parameters[''text'']}}'
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: container-io
 root:
diff --git a/sdk/python/test_data/components/container_no_input.py b/sdk/python/test_data/components/container_no_input.py
index 1a35eb3c47fc..f4f1fb526d0f 100644
--- a/sdk/python/test_data/components/container_no_input.py
+++ b/sdk/python/test_data/components/container_no_input.py
@@ -18,7 +18,7 @@
 @container_component
 def container_no_input():
     return ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=['echo', 'hello world'],
         args=[],
     )
diff --git a/sdk/python/test_data/components/container_no_input.yaml b/sdk/python/test_data/components/container_no_input.yaml
index a490a9c389da..23c30e59a42a 100644
--- a/sdk/python/test_data/components/container_no_input.yaml
+++ b/sdk/python/test_data/components/container_no_input.yaml
@@ -10,7 +10,7 @@ deploymentSpec:
         command:
         - echo
         - hello world
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: container-no-input
 root:
diff --git a/sdk/python/test_data/components/container_with_concat_placeholder.py b/sdk/python/test_data/components/container_with_concat_placeholder.py
index 707f71fd50ed..e3da70a38518 100644
--- a/sdk/python/test_data/components/container_with_concat_placeholder.py
+++ b/sdk/python/test_data/components/container_with_concat_placeholder.py
@@ -23,7 +23,7 @@
 def container_with_concat_placeholder(text1: str, text2: Output[Dataset],
                                       output_path: OutputPath(str)):
     return ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=[
             'my_program',
             ConcatPlaceholder(['prefix-', text1, text2.uri])
diff --git a/sdk/python/test_data/components/container_with_concat_placeholder.yaml b/sdk/python/test_data/components/container_with_concat_placeholder.yaml
index 8a1dba56da62..f0f02544f25f 100644
--- a/sdk/python/test_data/components/container_with_concat_placeholder.yaml
+++ b/sdk/python/test_data/components/container_with_concat_placeholder.yaml
@@ -31,7 +31,7 @@ deploymentSpec:
         command:
         - my_program
         - '{"Concat": ["prefix-", "{{$.inputs.parameters[''text1'']}}", "{{$.outputs.artifacts[''text2''].uri}}"]}'
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: container-with-concat-placeholder
 root:
diff --git a/sdk/python/test_data/components/container_with_if_placeholder.py b/sdk/python/test_data/components/container_with_if_placeholder.py
index b5e20e8ff9b6..7b21edc3e470 100644
--- a/sdk/python/test_data/components/container_with_if_placeholder.py
+++ b/sdk/python/test_data/components/container_with_if_placeholder.py
@@ -24,7 +24,7 @@ def container_with_if_placeholder(output_path: OutputPath(str),
                                   dataset: Output[Dataset],
                                   optional_input: str = 'default'):
     return ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=[
             'my_program',
             IfPresentPlaceholder(
diff --git a/sdk/python/test_data/components/container_with_if_placeholder.yaml b/sdk/python/test_data/components/container_with_if_placeholder.yaml
index 3b968d777760..65aec216d695 100644
--- a/sdk/python/test_data/components/container_with_if_placeholder.yaml
+++ b/sdk/python/test_data/components/container_with_if_placeholder.yaml
@@ -37,7 +37,7 @@ deploymentSpec:
         - --dataset
         - '{"IfPresent": {"InputName": "optional_input", "Then": ["{{$.outputs.artifacts[''dataset''].uri}}"],
           "Else": ["bye"]}}'
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: container-with-if-placeholder
 root:
diff --git a/sdk/python/test_data/components/container_with_placeholder_in_fstring.py b/sdk/python/test_data/components/container_with_placeholder_in_fstring.py
index 78103b7d00b8..e5bc2f5cb0b4 100644
--- a/sdk/python/test_data/components/container_with_placeholder_in_fstring.py
+++ b/sdk/python/test_data/components/container_with_placeholder_in_fstring.py
@@ -24,7 +24,7 @@ def container_with_placeholder_in_fstring(
     text1: str = 'text!',
 ):
     return ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=[
             'my_program',
             f'prefix-{text1}',
diff --git a/sdk/python/test_data/components/container_with_placeholder_in_fstring.yaml b/sdk/python/test_data/components/container_with_placeholder_in_fstring.yaml
index e1be212ad1bd..03949eafb502 100644
--- a/sdk/python/test_data/components/container_with_placeholder_in_fstring.yaml
+++ b/sdk/python/test_data/components/container_with_placeholder_in_fstring.yaml
@@ -27,7 +27,7 @@ deploymentSpec:
         - my_program
         - prefix-{{$.inputs.parameters['text1']}}
         - '{{$.outputs.artifacts[''output_artifact''].uri}}/0'
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: container-with-placeholder-in-fstring
 root:
diff --git a/sdk/python/test_data/components/containerized_python_component.py b/sdk/python/test_data/components/containerized_python_component.py
index 041722d97ff5..e32d4ad454c4 100644
--- a/sdk/python/test_data/components/containerized_python_component.py
+++ b/sdk/python/test_data/components/containerized_python_component.py
@@ -14,7 +14,7 @@
 from kfp import dsl
 
 
-@dsl.component(base_image='python:3.7', target_image='kfp-image')
+@dsl.component(base_image='python:3.9', target_image='kfp-image')
 def concat_message(message1: str, message2: str) -> str:
     return message1 + message2
 
diff --git a/sdk/python/test_data/components/dict_input.yaml b/sdk/python/test_data/components/dict_input.yaml
index 3fce18bdfe99..4bcf5e61d53e 100644
--- a/sdk/python/test_data/components/dict_input.yaml
+++ b/sdk/python/test_data/components/dict_input.yaml
@@ -38,7 +38,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef dict_input(struct: Dict):\n    print(struct)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: dict-input
 root:
diff --git a/sdk/python/test_data/components/identity.yaml b/sdk/python/test_data/components/identity.yaml
index 662a9bb81198..377911ccbcd7 100644
--- a/sdk/python/test_data/components/identity.yaml
+++ b/sdk/python/test_data/components/identity.yaml
@@ -44,7 +44,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef identity(value: str) -> str:\n    return value\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: identity
 root:
diff --git a/sdk/python/test_data/components/input_artifact.yaml b/sdk/python/test_data/components/input_artifact.yaml
index 80dbdd853b16..71c983fe36d8 100644
--- a/sdk/python/test_data/components/input_artifact.yaml
+++ b/sdk/python/test_data/components/input_artifact.yaml
@@ -41,7 +41,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef input_artifact(data: Input[Dataset]):\n    print(data.name)\n\
           \    print(data.uri)\n    print(data.metadata)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: input-artifact
 root:
diff --git a/sdk/python/test_data/components/nested_return.yaml b/sdk/python/test_data/components/nested_return.yaml
index 5c42937c8bf6..f8d2fd169ccd 100644
--- a/sdk/python/test_data/components/nested_return.yaml
+++ b/sdk/python/test_data/components/nested_return.yaml
@@ -39,7 +39,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef nested_return() -> List[Dict[str, str]]:\n    return [{'A_a':\
           \ '1', 'B_b': '2'}, {'A_a': '10', 'B_b': '20'}]\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: nested-return
 root:
diff --git a/sdk/python/test_data/components/output_metrics.yaml b/sdk/python/test_data/components/output_metrics.yaml
index dfb648a6b54a..fbde491a861b 100644
--- a/sdk/python/test_data/components/output_metrics.yaml
+++ b/sdk/python/test_data/components/output_metrics.yaml
@@ -45,7 +45,7 @@ deploymentSpec:
           \ that outputs metrics with a random accuracy.\"\"\"\n    import random\n\
           \    result = random.randint(0, 100)\n    metrics.log_metric('accuracy',\
           \ result)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: output-metrics
 root:
diff --git a/sdk/python/test_data/components/preprocess.yaml b/sdk/python/test_data/components/preprocess.yaml
index 5a4e387f668f..403154874687 100644
--- a/sdk/python/test_data/components/preprocess.yaml
+++ b/sdk/python/test_data/components/preprocess.yaml
@@ -97,7 +97,7 @@ deploymentSpec:
           \ 'w') as f:\n        f.write(json.dumps(input_dict_parameter))\n\n    with\
           \ open(output_list_parameter_path, 'w') as f:\n        f.write(json.dumps(input_list_parameter))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: preprocess
 root:
diff --git a/sdk/python/test_data/pipelines/component_with_optional_inputs.yaml b/sdk/python/test_data/pipelines/component_with_optional_inputs.yaml
index c6d725e4d6ff..b798786a8563 100644
--- a/sdk/python/test_data/pipelines/component_with_optional_inputs.yaml
+++ b/sdk/python/test_data/pipelines/component_with_optional_inputs.yaml
@@ -48,7 +48,7 @@ deploymentSpec:
           \ {input1}, type: {type(input1)}')\n    print(f'input2: {input2}, type:\
           \ {type(input2)}')\n    print(f'input3: {input3}, type: {type(input3)}')\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: v2-component-optional-input
 root:
diff --git a/sdk/python/test_data/pipelines/component_with_pip_index_urls.yaml b/sdk/python/test_data/pipelines/component_with_pip_index_urls.yaml
index 0359a4955c71..0358182f92b9 100644
--- a/sdk/python/test_data/pipelines/component_with_pip_index_urls.yaml
+++ b/sdk/python/test_data/pipelines/component_with_pip_index_urls.yaml
@@ -34,7 +34,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef component_op():\n    import yapf\n    print(dir(yapf))\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: v2-component-pip-index-urls
 root:
diff --git a/sdk/python/test_data/pipelines/components_with_optional_artifacts.yaml b/sdk/python/test_data/pipelines/components_with_optional_artifacts.yaml
index 9ffff4419e99..457902a8a51a 100644
--- a/sdk/python/test_data/pipelines/components_with_optional_artifacts.yaml
+++ b/sdk/python/test_data/pipelines/components_with_optional_artifacts.yaml
@@ -144,7 +144,7 @@ deploymentSpec:
           \ None):\n    if artifact is not None:\n        print(artifact.name)\n \
           \       print(artifact.uri)\n        print(artifact.metadata)\n    else:\n\
           \        print('No artifact provided!')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-python-artifact-printer-2:
       container:
         args:
@@ -175,7 +175,7 @@ deploymentSpec:
           \ None):\n    if artifact is not None:\n        print(artifact.name)\n \
           \       print(artifact.uri)\n        print(artifact.metadata)\n    else:\n\
           \        print('No artifact provided!')\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: optional-artifact-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/container_component_with_no_inputs.py b/sdk/python/test_data/pipelines/container_component_with_no_inputs.py
index 724b701dba10..da0c8e787351 100644
--- a/sdk/python/test_data/pipelines/container_component_with_no_inputs.py
+++ b/sdk/python/test_data/pipelines/container_component_with_no_inputs.py
@@ -19,7 +19,7 @@
 @dsl.container_component
 def hello_world_container():
     return dsl.ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=['echo', 'hello world'],
         args=[],
     )
diff --git a/sdk/python/test_data/pipelines/container_component_with_no_inputs.yaml b/sdk/python/test_data/pipelines/container_component_with_no_inputs.yaml
index 06ccc139ca2d..fba2c46ee030 100644
--- a/sdk/python/test_data/pipelines/container_component_with_no_inputs.yaml
+++ b/sdk/python/test_data/pipelines/container_component_with_no_inputs.yaml
@@ -10,7 +10,7 @@ deploymentSpec:
         command:
         - echo
         - hello world
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: v2-container-component-no-input
 root:
diff --git a/sdk/python/test_data/pipelines/cross_loop_after_topology.yaml b/sdk/python/test_data/pipelines/cross_loop_after_topology.yaml
index f95134646ca1..87d19b30d620 100644
--- a/sdk/python/test_data/pipelines/cross_loop_after_topology.yaml
+++ b/sdk/python/test_data/pipelines/cross_loop_after_topology.yaml
@@ -233,7 +233,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -261,7 +261,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-3:
       container:
         args:
@@ -289,7 +289,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-4:
       container:
         args:
@@ -317,7 +317,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-5:
       container:
         args:
@@ -345,7 +345,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-6:
       container:
         args:
@@ -373,7 +373,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-7:
       container:
         args:
@@ -401,7 +401,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-8:
       container:
         args:
@@ -429,7 +429,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/if_elif_else_complex.yaml b/sdk/python/test_data/pipelines/if_elif_else_complex.yaml
index 9950a23713ce..df2ff1c76ca9 100644
--- a/sdk/python/test_data/pipelines/if_elif_else_complex.yaml
+++ b/sdk/python/test_data/pipelines/if_elif_else_complex.yaml
@@ -712,7 +712,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef int_0_to_9999() -> int:\n    import random\n    return random.randint(0,\
           \ 9999)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-is-even-or-odd:
       container:
         args:
@@ -741,7 +741,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef is_even_or_odd(num: int) -> str:\n    return 'odd' if num % 2\
           \ else 'even'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-is-even-or-odd-2:
       container:
         args:
@@ -770,7 +770,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef is_even_or_odd(num: int) -> str:\n    return 'odd' if num % 2\
           \ else 'even'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return:
       container:
         args:
@@ -799,7 +799,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-2:
       container:
         args:
@@ -828,7 +828,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-3:
       container:
         args:
@@ -857,7 +857,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-4:
       container:
         args:
@@ -886,7 +886,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-5:
       container:
         args:
@@ -915,7 +915,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-6:
       container:
         args:
@@ -944,7 +944,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-7:
       container:
         args:
@@ -973,7 +973,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-8:
       container:
         args:
@@ -1002,7 +1002,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-9:
       container:
         args:
@@ -1031,7 +1031,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-ints:
       container:
         args:
@@ -1059,7 +1059,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_ints(ints: List[int]):\n    print(ints)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: lucky-number-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/if_elif_else_with_oneof_parameters.yaml b/sdk/python/test_data/pipelines/if_elif_else_with_oneof_parameters.yaml
index 2b558d3fc7e7..f6414225edaf 100644
--- a/sdk/python/test_data/pipelines/if_elif_else_with_oneof_parameters.yaml
+++ b/sdk/python/test_data/pipelines/if_elif_else_with_oneof_parameters.yaml
@@ -261,7 +261,7 @@ deploymentSpec:
           \ random.randint(0, 2)\n\n    if val == 0:\n        return 'heads'\n   \
           \ elif val == 1:\n        return 'tails'\n    else:\n        return 'draw'\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return:
       container:
         args:
@@ -290,7 +290,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-2:
       container:
         args:
@@ -319,7 +319,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-3:
       container:
         args:
@@ -348,7 +348,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-special-print-and-return:
       container:
         args:
@@ -378,7 +378,7 @@ deploymentSpec:
           \ *\n\ndef special_print_and_return(text: str, output_key: dsl.OutputPath(str)):\n\
           \    print('Got the special state:', text)\n    with open(output_key, 'w')\
           \ as f:\n        f.write(text)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: outer-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/if_else_with_oneof_artifacts.yaml b/sdk/python/test_data/pipelines/if_else_with_oneof_artifacts.yaml
index 5257218d766d..7ce1208b87ca 100644
--- a/sdk/python/test_data/pipelines/if_else_with_oneof_artifacts.yaml
+++ b/sdk/python/test_data/pipelines/if_else_with_oneof_artifacts.yaml
@@ -232,7 +232,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef flip_coin() -> str:\n    import random\n    return 'heads' if\
           \ random.randint(0, 1) == 0 else 'tails'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-param-to-artifact:
       container:
         args:
@@ -261,7 +261,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef param_to_artifact(val: str, a: Output[Artifact]):\n    with open(a.path,\
           \ 'w') as f:\n        f.write(val)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-param-to-artifact-2:
       container:
         args:
@@ -290,7 +290,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef param_to_artifact(val: str, a: Output[Artifact]):\n    with open(a.path,\
           \ 'w') as f:\n        f.write(val)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-artifact:
       container:
         args:
@@ -319,7 +319,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_artifact(a: Input[Artifact]):\n    with open(a.path) as\
           \ f:\n        print(f.read())\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-artifact-2:
       container:
         args:
@@ -348,7 +348,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_artifact(a: Input[Artifact]):\n    with open(a.path) as\
           \ f:\n        print(f.read())\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: outer-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/if_else_with_oneof_parameters.yaml b/sdk/python/test_data/pipelines/if_else_with_oneof_parameters.yaml
index 74a30f1283d9..aa2c7cf5a9f6 100644
--- a/sdk/python/test_data/pipelines/if_else_with_oneof_parameters.yaml
+++ b/sdk/python/test_data/pipelines/if_else_with_oneof_parameters.yaml
@@ -171,7 +171,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef flip_coin() -> str:\n    import random\n    return 'heads' if\
           \ random.randint(0, 1) == 0 else 'tails'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return:
       container:
         args:
@@ -200,7 +200,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-2:
       container:
         args:
@@ -229,7 +229,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-and-return-3:
       container:
         args:
@@ -258,7 +258,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_and_return(text: str) -> str:\n    print(text)\n    return\
           \ text\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: flip-coin-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/lightweight_python_functions_pipeline.yaml b/sdk/python/test_data/pipelines/lightweight_python_functions_pipeline.yaml
index 55cfdf7a49c6..52d0037d0ea4 100644
--- a/sdk/python/test_data/pipelines/lightweight_python_functions_pipeline.yaml
+++ b/sdk/python/test_data/pipelines/lightweight_python_functions_pipeline.yaml
@@ -119,7 +119,7 @@ deploymentSpec:
           \ 'w') as f:\n        f.write(json.dumps(input_dict_parameter))\n\n    with\
           \ open(output_list_parameter_path, 'w') as f:\n        f.write(json.dumps(input_list_parameter))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-train:
       container:
         args:
@@ -170,7 +170,7 @@ deploymentSpec:
           \ {i}\\n{line}\\n=====\\n')\n\n    # model is an instance of Model artifact,\
           \ which has a .metadata dictionary\n    # to store arbitrary metadata for\
           \ the output artifact.\n    model.metadata['accuracy'] = 0.9\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-test-pipeline-beta
 root:
diff --git a/sdk/python/test_data/pipelines/lightweight_python_functions_with_outputs.yaml b/sdk/python/test_data/pipelines/lightweight_python_functions_with_outputs.yaml
index 27fb096ab04b..e4dd740ff777 100644
--- a/sdk/python/test_data/pipelines/lightweight_python_functions_with_outputs.yaml
+++ b/sdk/python/test_data/pipelines/lightweight_python_functions_with_outputs.yaml
@@ -97,7 +97,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add_numbers(first: int, second: int) -> int:\n    return first\
           \ + second\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-concat-message:
       container:
         args:
@@ -126,7 +126,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef concat_message(first: str, second: str) -> str:\n    return first\
           \ + second\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-output-artifact:
       container:
         args:
@@ -155,7 +155,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef output_artifact(number: int, message: str) -> Dataset:\n    result\
           \ = [message for _ in range(number)]\n    return '\\n'.join(result)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-output-named-tuple:
       container:
         args:
@@ -191,7 +191,7 @@ deploymentSpec:
           \ = 'Model contents: ' + artifact_contents\n\n    from collections import\
           \ namedtuple\n    output = namedtuple('Outputs', ['scalar', 'metrics', 'model'])\n\
           \    return output(scalar, metrics, model)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: functions-with-outputs
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_complex.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_complex.yaml
index 8ce0dba9c9ad..6994b0a68dcd 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_complex.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_complex.yaml
@@ -304,7 +304,7 @@ deploymentSpec:
           \        with open(dataset.path) as f:\n            nums.append(int(f.read()))\n\
           \    with open(out_dataset.path, 'w') as f:\n        f.write(str(sum(nums)))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-add-2:
       container:
         args:
@@ -336,7 +336,7 @@ deploymentSpec:
           \        with open(dataset.path) as f:\n            nums.append(int(f.read()))\n\
           \    with open(out_dataset.path, 'w') as f:\n        f.write(str(sum(nums)))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-add-two-ints:
       container:
         args:
@@ -368,7 +368,7 @@ deploymentSpec:
           \ as f:\n        in_dataset1 = int(f.read())\n\n    with open(in_dataset2.path)\
           \ as f:\n        in_dataset2 = int(f.read())\n\n    with open(out_dataset.path,\
           \ 'w') as f:\n        f.write(str(in_dataset1 + in_dataset2))\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double:
       container:
         args:
@@ -398,7 +398,7 @@ deploymentSpec:
           \ *\n\ndef double(\n    num: int,\n    out_dataset: Output[Dataset],\n):\n\
           \    with open(out_dataset.path, 'w') as f:\n        f.write(str(2 * num))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-double-2:
       container:
         args:
@@ -428,7 +428,7 @@ deploymentSpec:
           \ *\n\ndef double(\n    num: int,\n    out_dataset: Output[Dataset],\n):\n\
           \    with open(out_dataset.path, 'w') as f:\n        f.write(str(2 * num))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.py b/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.py
index 5d49ae326805..04910311de0e 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.py
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.py
@@ -28,7 +28,7 @@ def add(in_datasets: Input[List[Dataset]], out_dataset: Output[Dataset]):
 def add_container(in_datasets: Input[List[Dataset]],
                   out_dataset: Output[Dataset]):
     return dsl.ContainerSpec(
-        image='python:3.7',
+        image='python:3.9',
         command=['python', '-c'],
         args=[
             textwrap.dedent("""
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.yaml
index 696c2d4a5614..e923d788ec2d 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/artifacts_simple.yaml
@@ -108,7 +108,7 @@ deploymentSpec:
           \    nums = []\n    for dataset in in_datasets:\n        with open(dataset.path)\
           \ as f:\n            nums.append(int(f.read()))\n    with open(out_dataset.path,\
           \ 'w') as f:\n        f.write(str(sum(nums)))\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-add-container:
       container:
         args:
@@ -125,7 +125,7 @@ deploymentSpec:
         command:
         - python
         - -c
-        image: python:3.7
+        image: python:3.9
     exec-double:
       container:
         args:
@@ -154,7 +154,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int, out_dataset: Output[Dataset]):\n    with open(out_dataset.path,\
           \ 'w') as f:\n        f.write(str(2 * num))\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/conditional_producer_and_consumers.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/conditional_producer_and_consumers.yaml
index accc5489e473..ac95760cb19f 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/conditional_producer_and_consumers.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/conditional_producer_and_consumers.yaml
@@ -147,7 +147,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add(nums: List[int]) -> int:\n    return sum(nums)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double:
       container:
         args:
@@ -175,7 +175,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/nested_with_parameters.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/nested_with_parameters.yaml
index 212dd4cee436..221ee317b5dc 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/nested_with_parameters.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/nested_with_parameters.yaml
@@ -166,7 +166,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add(nums: List[List[int]]) -> int:\n    import itertools\n  \
           \  return sum(itertools.chain(*nums))\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-add-two-nums:
       container:
         args:
@@ -194,7 +194,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add_two_nums(x: int, y: int) -> int:\n    return x + y\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double:
       container:
         args:
@@ -222,7 +222,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double-2:
       container:
         args:
@@ -250,7 +250,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_complex.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_complex.yaml
index 62e01b958b29..1fb44a7fd7ee 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_complex.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_complex.yaml
@@ -240,7 +240,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add_two_numbers(x: List[int], y: List[int]) -> int:\n    return\
           \ sum(x) + sum(y)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double:
       container:
         args:
@@ -268,7 +268,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double-2:
       container:
         args:
@@ -296,7 +296,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-nested-add:
       container:
         args:
@@ -325,7 +325,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef nested_add(nums: List[List[int]]) -> int:\n    import itertools\n\
           \    return sum(itertools.chain(*nums))\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-nested-add-2:
       container:
         args:
@@ -354,7 +354,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef nested_add(nums: List[List[int]]) -> int:\n    import itertools\n\
           \    return sum(itertools.chain(*nums))\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-simple-add:
       container:
         args:
@@ -382,7 +382,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef simple_add(nums: List[int]) -> int:\n    return sum(nums)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-simple-add-2:
       container:
         args:
@@ -410,7 +410,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef simple_add(nums: List[int]) -> int:\n    return sum(nums)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_simple.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_simple.yaml
index c65a6819aad6..47fb058803fb 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_simple.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/parameters_simple.yaml
@@ -90,7 +90,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add(nums: List[int]) -> int:\n    return sum(nums)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-add-container:
       container:
         args:
@@ -128,7 +128,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/parallelfor_fan_in/pipeline_producer_consumer.yaml b/sdk/python/test_data/pipelines/parallelfor_fan_in/pipeline_producer_consumer.yaml
index 17c36ffd54b6..015d9066115c 100644
--- a/sdk/python/test_data/pipelines/parallelfor_fan_in/pipeline_producer_consumer.yaml
+++ b/sdk/python/test_data/pipelines/parallelfor_fan_in/pipeline_producer_consumer.yaml
@@ -222,7 +222,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add(nums: List[List[int]]) -> int:\n    import itertools\n  \
           \  return sum(itertools.chain(*nums))\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-double:
       container:
         args:
@@ -250,7 +250,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef double(num: int) -> int:\n    return 2 * num\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-echo-and-return:
       container:
         args:
@@ -279,7 +279,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef echo_and_return(string: str) -> str:\n    print(string)\n   \
           \ return string\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-join-and-print:
       container:
         args:
@@ -308,7 +308,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef join_and_print(strings: List[str]):\n    print(''.join(strings))\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: math-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_as_exit_task.yaml b/sdk/python/test_data/pipelines/pipeline_as_exit_task.yaml
index 5af88cffd513..13bfb5acd14b 100644
--- a/sdk/python/test_data/pipelines/pipeline_as_exit_task.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_as_exit_task.yaml
@@ -145,7 +145,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n\
           \    print(message)\n    sys.exit(1)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-get-run-state:
       container:
         args:
@@ -174,7 +174,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef get_run_state(status: dict) -> str:\n    print('Pipeline status:\
           \ ', status)\n    return status['state']\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -203,7 +203,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -232,7 +232,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-task-final-status-conditional
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_in_pipeline.yaml b/sdk/python/test_data/pipelines/pipeline_in_pipeline.yaml
index aa3fd1518b8c..45efa979a990 100644
--- a/sdk/python/test_data/pipelines/pipeline_in_pipeline.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_in_pipeline.yaml
@@ -90,7 +90,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op1-2:
       container:
         args:
@@ -119,7 +119,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op2:
       container:
         command:
diff --git a/sdk/python/test_data/pipelines/pipeline_in_pipeline_complex.yaml b/sdk/python/test_data/pipelines/pipeline_in_pipeline_complex.yaml
index 720d7aa7d8e4..268581c358a4 100644
--- a/sdk/python/test_data/pipelines/pipeline_in_pipeline_complex.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_in_pipeline_complex.yaml
@@ -177,7 +177,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op1-2:
       container:
         args:
@@ -206,7 +206,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op2:
       container:
         command:
diff --git a/sdk/python/test_data/pipelines/pipeline_in_pipeline_loaded_from_yaml.yaml b/sdk/python/test_data/pipelines/pipeline_in_pipeline_loaded_from_yaml.yaml
index 98e95d507886..97977ea3d991 100644
--- a/sdk/python/test_data/pipelines/pipeline_in_pipeline_loaded_from_yaml.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_in_pipeline_loaded_from_yaml.yaml
@@ -168,7 +168,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op1-2:
       container:
         args:
@@ -197,7 +197,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op1-3:
       container:
         args:
@@ -226,7 +226,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(data: Input[Artifact]):\n    with open(data.path, 'r')\
           \ as f:\n        print(f.read())\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op2:
       container:
         args:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_condition.yaml b/sdk/python/test_data/pipelines/pipeline_with_condition.yaml
index 0b73afcd1b98..eb3504889706 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_condition.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_condition.yaml
@@ -105,7 +105,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-flip-coin-op-2:
       container:
         args:
@@ -135,7 +135,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -164,7 +164,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -193,7 +193,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-3:
       container:
         args:
@@ -222,7 +222,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: single-condition-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_condition_dynamic_task_output_custom_training_job.yaml b/sdk/python/test_data/pipelines/pipeline_with_condition_dynamic_task_output_custom_training_job.yaml
index 9c233c63ddee..12754cacc2f6 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_condition_dynamic_task_output_custom_training_job.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_condition_dynamic_task_output_custom_training_job.yaml
@@ -222,7 +222,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef accelerator_count() -> int:\n    return 1\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-accelerator-type:
       container:
         args:
@@ -250,7 +250,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef accelerator_type() -> str:\n    return 'NVIDIA_TESLA_P4'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-custom-training-job:
       container:
         args:
@@ -307,7 +307,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef flip_biased_coin_op() -> str:\n    \"\"\"Flip a coin and output\
           \ heads.\"\"\"\n    return 'heads'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-machine-type:
       container:
         args:
@@ -335,7 +335,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef machine_type() -> str:\n    return 'n1-standard-4'\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_dynamic_importer_metadata.yaml b/sdk/python/test_data/pipelines/pipeline_with_dynamic_importer_metadata.yaml
index 0804b87190d4..3e788001c0eb 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_dynamic_importer_metadata.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_dynamic_importer_metadata.yaml
@@ -109,7 +109,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef make_name(name: str) -> str:\n    return name\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-importer
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_dynamic_task_output_custom_training_job.yaml b/sdk/python/test_data/pipelines/pipeline_with_dynamic_task_output_custom_training_job.yaml
index 52caab3e992f..3c688b6bab30 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_dynamic_task_output_custom_training_job.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_dynamic_task_output_custom_training_job.yaml
@@ -159,7 +159,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef accelerator_count() -> int:\n    return 1\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-accelerator-type:
       container:
         args:
@@ -187,7 +187,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef accelerator_type() -> str:\n    return 'NVIDIA_TESLA_P4'\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-custom-training-job:
       container:
         args:
@@ -243,7 +243,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef machine_type() -> str:\n    return 'n1-standard-4'\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_env.yaml b/sdk/python/test_data/pipelines/pipeline_with_env.yaml
index 24f410b28515..9663641b9ee5 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_env.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_env.yaml
@@ -60,7 +60,7 @@ deploymentSpec:
         env:
         - name: ENV1
           value: val1
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-env
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_exit_handler.yaml b/sdk/python/test_data/pipelines/pipeline_with_exit_handler.yaml
index c23f4ffbd0e7..ca5d65cd4086 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_exit_handler.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_exit_handler.yaml
@@ -81,7 +81,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n\
           \    print(message)\n    sys.exit(1)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -110,7 +110,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -139,7 +139,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-exit-handler
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_google_artifact_type.yaml b/sdk/python/test_data/pipelines/pipeline_with_google_artifact_type.yaml
index c5bad0731e9b..ae54d2aef4dc 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_google_artifact_type.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_google_artifact_type.yaml
@@ -79,7 +79,7 @@ deploymentSpec:
           \  print('Dataset')\n    print('artifact.type: ', type(dataset))\n    print('artifact.name:\
           \ ', dataset.name)\n    print('artifact.uri: ', dataset.uri)\n    print('artifact.metadata:\
           \ ', dataset.metadata)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-model-producer:
       container:
         args:
@@ -110,7 +110,7 @@ deploymentSpec:
           \ *\nimport aiplatform\n\ndef model_producer(model: Output[aiplatform.VertexModel]):\n\
           \n    assert isinstance(model, aiplatform.VertexModel), type(model)\n  \
           \  with open(model.path, 'w') as f:\n        f.write('my model')\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-google-types
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_importer.yaml b/sdk/python/test_data/pipelines/pipeline_with_importer.yaml
index a466c9f143c6..530a881afa4c 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_importer.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_importer.yaml
@@ -148,7 +148,7 @@ deploymentSpec:
           \ trained using data: {data}'\n\n    from collections import namedtuple\n\
           \    output = namedtuple('Outputs', ['scalar', 'model'])\n    return output(scalar,\
           \ model)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-train-2:
       container:
         args:
@@ -182,7 +182,7 @@ deploymentSpec:
           \ trained using data: {data}'\n\n    from collections import namedtuple\n\
           \    output = namedtuple('Outputs', ['scalar', 'model'])\n    return output(scalar,\
           \ model)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-importer
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_loops.yaml b/sdk/python/test_data/pipelines/pipeline_with_loops.yaml
index 93e63cfa8a8a..df8c9c3fc69b 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_loops.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_loops.yaml
@@ -187,7 +187,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef args_generator_op() -> List[Dict[str, str]]:\n    return [{'A_a':\
           \ '1', 'B_b': '2'}, {'A_a': '10', 'B_b': '20'}]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-struct:
       container:
         args:
@@ -215,7 +215,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_struct(struct: Dict):\n    print(struct)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-struct-2:
       container:
         args:
@@ -243,7 +243,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_struct(struct: Dict):\n    print(struct)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text:
       container:
         args:
@@ -271,7 +271,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-2:
       container:
         args:
@@ -299,7 +299,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-3:
       container:
         args:
@@ -327,7 +327,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-4:
       container:
         args:
@@ -355,7 +355,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-5:
       container:
         args:
@@ -383,7 +383,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-loops
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_loops_and_conditions.yaml b/sdk/python/test_data/pipelines/pipeline_with_loops_and_conditions.yaml
index b307e9bc0f2b..77ae492d7023 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_loops_and_conditions.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_loops_and_conditions.yaml
@@ -620,7 +620,7 @@ deploymentSpec:
           \       'A_a': '1',\n            'B_b': ['2', '20'],\n        },\n     \
           \   {\n            'A_a': '10',\n            'B_b': ['22', '222'],\n   \
           \     },\n    ]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-args-generator-op-2:
       container:
         args:
@@ -651,7 +651,7 @@ deploymentSpec:
           \       'A_a': '1',\n            'B_b': ['2', '20'],\n        },\n     \
           \   {\n            'A_a': '10',\n            'B_b': ['22', '222'],\n   \
           \     },\n    ]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-flip-coin-op:
       container:
         args:
@@ -681,7 +681,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-struct:
       container:
         args:
@@ -709,7 +709,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_struct(struct: dict):\n    print(struct)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text:
       container:
         args:
@@ -738,7 +738,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-2:
       container:
         args:
@@ -767,7 +767,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-3:
       container:
         args:
@@ -796,7 +796,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-4:
       container:
         args:
@@ -825,7 +825,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-5:
       container:
         args:
@@ -854,7 +854,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-6:
       container:
         args:
@@ -883,7 +883,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-7:
       container:
         args:
@@ -912,7 +912,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-8:
       container:
         args:
@@ -941,7 +941,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-9:
       container:
         args:
@@ -970,7 +970,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-loops-and-conditions-multi-layers
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_metadata_fields.yaml b/sdk/python/test_data/pipelines/pipeline_with_metadata_fields.yaml
index db8b4d54a5d8..b3181c95edab 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_metadata_fields.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_metadata_fields.yaml
@@ -84,7 +84,7 @@ deploymentSpec:
           \ as f:\n        content_b = f.read()\n\n    concatenated_string = content_a\
           \ + content_b\n    with open(out_dataset.path, 'w') as f:\n        f.write(concatenated_string)\n\
           \n    return concatenated_string\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-str-to-dataset:
       container:
         args:
@@ -115,7 +115,7 @@ deploymentSpec:
           \"\"Convert string to dataset.\n\n    Args:\n        string: The string.\n\
           \n    Returns:\n        dataset: The dataset.\n    \"\"\"\n    with open(dataset.path,\
           \ 'w') as f:\n        f.write(string)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   description: A pipeline that joins string to in_dataset.
   displayName: Concatenation pipeline
diff --git a/sdk/python/test_data/pipelines/pipeline_with_metrics_outputs.yaml b/sdk/python/test_data/pipelines/pipeline_with_metrics_outputs.yaml
index 3f3fd49d1c2a..d325d84caefb 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_metrics_outputs.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_metrics_outputs.yaml
@@ -78,7 +78,7 @@ deploymentSpec:
           \ that outputs metrics with a random accuracy.\"\"\"\n    import random\n\
           \    result = random.randint(0, 100)\n    metrics.log_metric('accuracy',\
           \ result)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-output-metrics-2:
       container:
         args:
@@ -109,7 +109,7 @@ deploymentSpec:
           \ that outputs metrics with a random accuracy.\"\"\"\n    import random\n\
           \    result = random.randint(0, 100)\n    metrics.log_metric('accuracy',\
           \ result)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-metrics-outputs
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_multiple_exit_handlers.yaml b/sdk/python/test_data/pipelines/pipeline_with_multiple_exit_handlers.yaml
index 93fbda59311e..1e99f2eb8cf1 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_multiple_exit_handlers.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_multiple_exit_handlers.yaml
@@ -141,7 +141,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n\
           \    print(message)\n    sys.exit(1)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -170,7 +170,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -199,7 +199,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-3:
       container:
         args:
@@ -228,7 +228,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-4:
       container:
         args:
@@ -257,7 +257,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-5:
       container:
         args:
@@ -286,7 +286,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-6:
       container:
         args:
@@ -315,7 +315,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-multiple-exit-handlers
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_nested_conditions.yaml b/sdk/python/test_data/pipelines/pipeline_with_nested_conditions.yaml
index 526a5548f273..62b04e0f2ab6 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_nested_conditions.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_nested_conditions.yaml
@@ -164,7 +164,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-flip-coin-op-2:
       container:
         args:
@@ -194,7 +194,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-flip-coin-op-3:
       container:
         args:
@@ -224,7 +224,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-flip-coin-op-4:
       container:
         args:
@@ -254,7 +254,7 @@ deploymentSpec:
           \ *\n\ndef flip_coin_op() -> str:\n    \"\"\"Flip a coin and output heads\
           \ or tails randomly.\"\"\"\n    import random\n    result = 'heads' if random.randint(0,\
           \ 1) == 0 else 'tails'\n    return result\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -283,7 +283,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -312,7 +312,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-3:
       container:
         args:
@@ -341,7 +341,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-4:
       container:
         args:
@@ -370,7 +370,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str):\n    \"\"\"Print a message.\"\"\"\n    print(msg)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: nested-conditions-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.py b/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.py
index 89e22ed117a7..03e7589352f3 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.py
+++ b/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.py
@@ -25,7 +25,7 @@ def random_num_op(low, high):
       - {name: output, type: Integer}
       implementation:
         container:
-          image: python:alpine3.6
+          image: python:alpine3.9
           command:
           - sh
           - -c
@@ -43,7 +43,7 @@ def random_num_op(low, high):
       - {name: output, type: String}
       implementation:
         container:
-          image: python:alpine3.6
+          image: python:alpine3.9
           command:
           - sh
           - -c
@@ -58,7 +58,7 @@ def random_num_op(low, high):
       - {name: msg, type: String}
       implementation:
         container:
-          image: python:alpine3.6
+          image: python:alpine3.9
           command:
           - echo
           - {inputValue: msg}
diff --git a/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.yaml b/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.yaml
index f2e06ddd004e..ef6d01cd86b0 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_nested_conditions_yaml.yaml
@@ -251,7 +251,7 @@ deploymentSpec:
         command:
         - sh
         - -c
-        image: python:alpine3.6
+        image: python:alpine3.9
     exec-generate-random-number:
       container:
         args:
@@ -263,7 +263,7 @@ deploymentSpec:
         command:
         - sh
         - -c
-        image: python:alpine3.6
+        image: python:alpine3.9
     exec-generate-random-number-2:
       container:
         args:
@@ -275,31 +275,31 @@ deploymentSpec:
         command:
         - sh
         - -c
-        image: python:alpine3.6
+        image: python:alpine3.9
     exec-print:
       container:
         command:
         - echo
         - '{{$.inputs.parameters[''msg'']}}'
-        image: python:alpine3.6
+        image: python:alpine3.9
     exec-print-2:
       container:
         command:
         - echo
         - '{{$.inputs.parameters[''msg'']}}'
-        image: python:alpine3.6
+        image: python:alpine3.9
     exec-print-3:
       container:
         command:
         - echo
         - '{{$.inputs.parameters[''msg'']}}'
-        image: python:alpine3.6
+        image: python:alpine3.9
     exec-print-4:
       container:
         command:
         - echo
         - '{{$.inputs.parameters[''msg'']}}'
-        image: python:alpine3.6
+        image: python:alpine3.9
 pipelineInfo:
   description: Shows how to use dsl.Condition().
   displayName: Conditional execution pipeline.
diff --git a/sdk/python/test_data/pipelines/pipeline_with_nested_loops.yaml b/sdk/python/test_data/pipelines/pipeline_with_nested_loops.yaml
index c50196e9a122..960d091d1ef3 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_nested_loops.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_nested_loops.yaml
@@ -161,7 +161,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -190,7 +190,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-3:
       container:
         args:
@@ -219,7 +219,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, msg2: Optional[str] = None):\n    print(f'msg:\
           \ {msg}, msg2: {msg2}')\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-nested-loops
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_outputs.yaml b/sdk/python/test_data/pipelines/pipeline_with_outputs.yaml
index a40f5b20fce6..914937e18f4d 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_outputs.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_outputs.yaml
@@ -120,7 +120,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op1-2:
       container:
         args:
@@ -149,7 +149,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op1(msg: str) -> str:\n    print(msg)\n    return msg\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op2:
       container:
         args:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_parallelfor_list_artifacts.yaml b/sdk/python/test_data/pipelines/pipeline_with_parallelfor_list_artifacts.yaml
index 7fd8b8227936..7df9b8930a9a 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_parallelfor_list_artifacts.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_parallelfor_list_artifacts.yaml
@@ -274,7 +274,7 @@ deploymentSpec:
           \ *\n\ndef make_artifact(data: str) -> Artifact:\n    artifact = Artifact(uri=dsl.get_uri(),\
           \ metadata={'length': len(data)})\n    with open(artifact.path, 'w') as\
           \ f:\n        f.write(data)\n    return artifact\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-make-dataset:
       container:
         args:
@@ -304,7 +304,7 @@ deploymentSpec:
           \ *\n\ndef make_dataset(data: str) -> Dataset:\n    dataset = Dataset(uri=dsl.get_uri(),\
           \ metadata={'length': len(data)})\n    with open(dataset.path, 'w') as f:\n\
           \        f.write(data)\n    return dataset\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-artifact-name:
       container:
         args:
@@ -333,7 +333,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_artifact_name(artifact: Artifact) -> str:\n    print(artifact.name)\n\
           \    return artifact.name\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-artifact-name-2:
       container:
         args:
@@ -362,7 +362,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_artifact_name(artifact: Artifact) -> str:\n    print(artifact.name)\n\
           \    return artifact.name\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-parallelfor-artifacts
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_parallelfor_parallelism.yaml b/sdk/python/test_data/pipelines/pipeline_with_parallelfor_parallelism.yaml
index a33fc357221f..0fcf820fc14e 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_parallelfor_parallelism.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_parallelfor_parallelism.yaml
@@ -388,7 +388,7 @@ deploymentSpec:
           \ are strings and values are integers. For testing type \n    handling during\
           \ compilation.\"\"\"\n    return [{'a': 1, 'b': 2}, {'a': 2, 'b': 3}, {'a':\
           \ 3, 'b': 4}]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-list-dict-maker-1:
       container:
         args:
@@ -419,7 +419,7 @@ deploymentSpec:
           \ dictionary typing (no enforcement of specific key or\n    value types).\n\
           \n    Tests flexibility in type handling.\n    \"\"\"\n    return [{'a':\
           \ 1, 'b': 2}, {'a': 2, 'b': 3}, {'a': 3, 'b': 4}]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-list-dict-maker-1-2:
       container:
         args:
@@ -450,7 +450,7 @@ deploymentSpec:
           \ dictionary typing (no enforcement of specific key or\n    value types).\n\
           \n    Tests flexibility in type handling.\n    \"\"\"\n    return [{'a':\
           \ 1, 'b': 2}, {'a': 2, 'b': 3}, {'a': 3, 'b': 4}]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-list-dict-maker-2:
       container:
         args:
@@ -481,7 +481,7 @@ deploymentSpec:
           \ of dictionaries without type enforcement.\n\n    Tests flexibility in\
           \ type handling.\n    \"\"\"\n    return [{'a': 1, 'b': 2}, {'a': 2, 'b':\
           \ 3}, {'a': 3, 'b': 4}]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-list-dict-maker-3:
       container:
         args:
@@ -512,7 +512,7 @@ deploymentSpec:
           \ (no typing or structure guarantees).\n\n    Tests the limits of compiler\
           \ type handling.\n    \"\"\"\n    return [{'a': 1, 'b': 2}, {'a': 2, 'b':\
           \ 3}, {'a': 3, 'b': 4}]\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-int:
       container:
         args:
@@ -540,7 +540,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_int(x: int):\n    print(x)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-int-2:
       container:
         args:
@@ -568,7 +568,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_int(x: int):\n    print(x)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-int-3:
       container:
         args:
@@ -596,7 +596,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_int(x: int):\n    print(x)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-int-4:
       container:
         args:
@@ -624,7 +624,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_int(x: int):\n    print(x)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-int-5:
       container:
         args:
@@ -652,7 +652,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_int(x: int):\n    print(x)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-int-6:
       container:
         args:
@@ -680,7 +680,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_int(x: int):\n    print(x)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text:
       container:
         args:
@@ -708,7 +708,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-2:
       container:
         args:
@@ -736,7 +736,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-3:
       container:
         args:
@@ -764,7 +764,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-4:
       container:
         args:
@@ -792,7 +792,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-5:
       container:
         args:
@@ -820,7 +820,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-text-6:
       container:
         args:
@@ -848,7 +848,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_text(msg: str):\n    print(msg)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-loops
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_params_containing_format.yaml b/sdk/python/test_data/pipelines/pipeline_with_params_containing_format.yaml
index cadad9a1af91..2ca766c8f3b3 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_params_containing_format.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_params_containing_format.yaml
@@ -90,7 +90,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(text: str) -> str:\n    print(text)\n    return text\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -119,7 +119,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(text: str) -> str:\n    print(text)\n    return text\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op2:
       container:
         args:
@@ -148,7 +148,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op2(text1: str, text2: str) -> str:\n    print(text1 +\
           \ text2)\n    return text1 + text2\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-pipelineparam-containing-format
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_placeholders.yaml b/sdk/python/test_data/pipelines/pipeline_with_placeholders.yaml
index 8f8cc765ac4e..44f63c95d613 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_placeholders.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_placeholders.yaml
@@ -70,7 +70,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, value: str):\n    print(msg, value)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-2:
       container:
         args:
@@ -98,7 +98,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, value: str):\n    print(msg, value)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-3:
       container:
         args:
@@ -126,7 +126,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, value: str):\n    print(msg, value)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-4:
       container:
         args:
@@ -154,7 +154,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, value: str):\n    print(msg, value)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op-5:
       container:
         args:
@@ -182,7 +182,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(msg: str, value: str):\n    print(msg, value)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-placeholders
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_retry.yaml b/sdk/python/test_data/pipelines/pipeline_with_retry.yaml
index 7e67e70a8aca..e82aefc825b4 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_retry.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_retry.yaml
@@ -45,7 +45,7 @@ deploymentSpec:
           '
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef add(a: float, b: float) -> float:\n    return a + b\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: test-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_task_final_status.yaml b/sdk/python/test_data/pipelines/pipeline_with_task_final_status.yaml
index 59a781c55f7e..61c916495cde 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_task_final_status.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_task_final_status.yaml
@@ -88,7 +88,7 @@ deploymentSpec:
           \    print('Pipeline task name: ', status.pipeline_task_name)\n    print('Error\
           \ code: ', status.error_code)\n    print('Error message: ', status.error_message)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-fail-op:
       container:
         args:
@@ -117,7 +117,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n\
           \    print(message)\n    sys.exit(1)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -146,7 +146,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-task-final-status
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.py b/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.py
index 6cf1282009ca..caada43bc533 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.py
+++ b/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.py
@@ -24,7 +24,7 @@
 - {name: status, type: PipelineTaskFinalStatus}
 implementation:
   container:
-    image: python:3.7
+    image: python:3.9
     command:
     - echo
     - "user input:"
@@ -39,7 +39,7 @@
 - {name: message, type: String}
 implementation:
   container:
-    image: python:3.7
+    image: python:3.9
     command:
     - echo
     - {inputValue: message}
diff --git a/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.yaml b/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.yaml
index 598293b89588..fd6ef9e3a852 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_task_final_status_yaml.yaml
@@ -46,13 +46,13 @@ deploymentSpec:
         - '{{$.inputs.parameters[''user_input'']}}'
         - 'pipeline status:'
         - '{{$.inputs.parameters[''status'']}}'
-        image: python:3.7
+        image: python:3.9
     exec-print-op:
       container:
         command:
         - echo
         - '{{$.inputs.parameters[''message'']}}'
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-task-final-status-yaml
 root:
diff --git a/sdk/python/test_data/pipelines/pipeline_with_task_using_ignore_upstream_failure.yaml b/sdk/python/test_data/pipelines/pipeline_with_task_using_ignore_upstream_failure.yaml
index 4a94204f4d7f..ffc0928698ab 100644
--- a/sdk/python/test_data/pipelines/pipeline_with_task_using_ignore_upstream_failure.yaml
+++ b/sdk/python/test_data/pipelines/pipeline_with_task_using_ignore_upstream_failure.yaml
@@ -51,7 +51,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef fail_op(message: str) -> str:\n    \"\"\"Fails.\"\"\"\n    import\
           \ sys\n    print(message)\n    sys.exit(1)\n    return message\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -80,7 +80,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str = 'default'):\n    \"\"\"Prints a message.\"\
           \"\"\n    print(message)\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: my-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pythonic_artifact_with_single_return.yaml b/sdk/python/test_data/pipelines/pythonic_artifact_with_single_return.yaml
index eebea12d07b7..fa6aa54dae0b 100644
--- a/sdk/python/test_data/pipelines/pythonic_artifact_with_single_return.yaml
+++ b/sdk/python/test_data/pipelines/pythonic_artifact_with_single_return.yaml
@@ -74,7 +74,7 @@ deploymentSpec:
           \ str) -> str:\n        return x\n\n    model = Model(\n        uri=dsl.get_uri(suffix='model'),\n\
           \        metadata={'data': text_dataset.name},\n    )\n\n    with open(model.path,\
           \ 'wb') as f:\n        dill.dump(dummy_model, f)\n\n    return model\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: make-language-model-pipeline
 root:
diff --git a/sdk/python/test_data/pipelines/pythonic_artifacts_with_list_of_artifacts.yaml b/sdk/python/test_data/pipelines/pythonic_artifacts_with_list_of_artifacts.yaml
index 8daa740d65fa..985e26f026a9 100644
--- a/sdk/python/test_data/pipelines/pythonic_artifacts_with_list_of_artifacts.yaml
+++ b/sdk/python/test_data/pipelines/pythonic_artifacts_with_list_of_artifacts.yaml
@@ -97,7 +97,7 @@ deploymentSpec:
           \ = []\n    for dataset in datasets:\n        with open(dataset.path, 'r')\
           \ as f:\n            texts.append(f.read())\n\n    return ''.join(texts)\n\
           \n"
-        image: python:3.8
+        image: python:3.9
     exec-make-dataset:
       container:
         args:
@@ -127,7 +127,7 @@ deploymentSpec:
           \ *\n\ndef make_dataset(text: str) -> Dataset:\n    dataset = Dataset(uri=dsl.get_uri(),\
           \ metadata={'length': len(text)})\n    with open(dataset.path, 'w') as f:\n\
           \        f.write(text)\n    return dataset\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: make-and-join-datasets
 root:
diff --git a/sdk/python/test_data/pipelines/pythonic_artifacts_with_multiple_returns.yaml b/sdk/python/test_data/pipelines/pythonic_artifacts_with_multiple_returns.yaml
index fd3360e24ebb..247484fbe28a 100644
--- a/sdk/python/test_data/pipelines/pythonic_artifacts_with_multiple_returns.yaml
+++ b/sdk/python/test_data/pipelines/pythonic_artifacts_with_multiple_returns.yaml
@@ -110,7 +110,7 @@ deploymentSpec:
           \      f.write(out_data2)\n\n    outputs = NamedTuple(\n        'outputs',\n\
           \        dataset1=Dataset,\n        dataset2=Dataset,\n    )\n    return\
           \ outputs(dataset1=dataset1, dataset2=dataset2)\n\n"
-        image: python:3.8
+        image: python:3.9
     exec-make-dataset:
       container:
         args:
@@ -140,7 +140,7 @@ deploymentSpec:
           \ *\n\ndef make_dataset() -> Artifact:\n    artifact = Artifact(uri=dsl.get_uri('dataset'))\n\
           \    with open(artifact.path, 'w') as f:\n        f.write('Hello, world')\n\
           \    return artifact\n\n"
-        image: python:3.8
+        image: python:3.9
 pipelineInfo:
   name: split-datasets-and-return-first
 root:
diff --git a/sdk/python/test_data/pipelines/xgboost_sample_pipeline.py b/sdk/python/test_data/pipelines/xgboost_sample_pipeline.py
deleted file mode 100644
index cb40d4905d3a..000000000000
--- a/sdk/python/test_data/pipelines/xgboost_sample_pipeline.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# Copyright 2021 The Kubeflow Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from kfp import compiler
-from kfp import components
-from kfp import dsl
-
-chicago_taxi_dataset_op = components.load_component_from_url(
-    'https://raw.githubusercontent.com/kubeflow/pipelines/60a2612541ec08c6a85c237d2ec7525b12543a43/components/datasets/Chicago_Taxi_Trips/component.yaml'
-)
-convert_csv_to_apache_parquet_op = components.load_component_from_url(
-    'https://raw.githubusercontent.com/kubeflow/pipelines/0d7d6f41c92bdc05c2825232afe2b47e5cb6c4b3/components/_converters/ApacheParquet/from_CSV/component.yaml'
-)
-xgboost_train_on_csv_op = components.load_component_from_url(
-    'https://raw.githubusercontent.com/kubeflow/pipelines/567c04c51ff00a1ee525b3458425b17adbe3df61/components/XGBoost/Train/component.yaml'
-)
-xgboost_predict_on_csv_op = components.load_component_from_url(
-    'https://raw.githubusercontent.com/kubeflow/pipelines/31939086d66d633732f75300ce69eb60e9fb0269/components/XGBoost/Predict/component.yaml'
-)
-xgboost_train_on_parquet_op = components.load_component_from_url(
-    'https://raw.githubusercontent.com/kubeflow/pipelines/0ae2f30ff24beeef1c64cc7c434f1f652c065192/components/XGBoost/Train/from_ApacheParquet/component.yaml'
-)
-xgboost_predict_on_parquet_op = components.load_component_from_url(
-    'https://raw.githubusercontent.com/kubeflow/pipelines/31939086d66d633732f75300ce69eb60e9fb0269/components/XGBoost/Predict/from_ApacheParquet/component.yaml'
-)
-
-
-@dsl.pipeline(name='xgboost-sample-pipeline')
-def xgboost_pipeline():
-    training_data_csv = chicago_taxi_dataset_op(
-        where='trip_start_timestamp >= "2019-01-01" AND trip_start_timestamp < "2019-02-01"',
-        select='tips,trip_seconds,trip_miles,pickup_community_area,dropoff_community_area,fare,tolls,extras,trip_total',
-        limit=10000,
-    ).output
-
-    # Training and prediction on dataset in CSV format
-    model_trained_on_csv = xgboost_train_on_csv_op(
-        training_data=training_data_csv,
-        label_column=0,
-        objective='reg:squarederror',
-        num_iterations=200,
-    ).outputs['model']
-
-    xgboost_predict_on_csv_op(
-        data=training_data_csv,
-        model=model_trained_on_csv,
-        label_column=0,
-    )
-
-    # Training and prediction on dataset in Apache Parquet format
-    training_data_parquet = convert_csv_to_apache_parquet_op(
-        data=training_data_csv).output
-
-    model_trained_on_parquet = xgboost_train_on_parquet_op(
-        training_data=training_data_parquet,
-        label_column_name='tips',
-        objective='reg:squarederror',
-        num_iterations=200,
-    ).outputs['model']
-
-    xgboost_predict_on_parquet_op(
-        data=training_data_parquet,
-        model=model_trained_on_parquet,
-        label_column_name='tips',
-    )
-
-    # Checking cross-format predictions
-    xgboost_predict_on_parquet_op(
-        data=training_data_parquet,
-        model=model_trained_on_csv,
-        label_column_name='tips',
-    )
-
-    xgboost_predict_on_csv_op(
-        data=training_data_csv,
-        model=model_trained_on_parquet,
-        label_column=0,
-    )
-
-
-if __name__ == '__main__':
-    compiler.Compiler().compile(
-        pipeline_func=xgboost_pipeline,
-        package_path=__file__.replace('.py', '.yaml'))
diff --git a/sdk/python/test_data/pipelines/xgboost_sample_pipeline.yaml b/sdk/python/test_data/pipelines/xgboost_sample_pipeline.yaml
deleted file mode 100644
index 2e03d06edff1..000000000000
--- a/sdk/python/test_data/pipelines/xgboost_sample_pipeline.yaml
+++ /dev/null
@@ -1,926 +0,0 @@
-# PIPELINE DEFINITION
-# Name: xgboost-sample-pipeline
-components:
-  comp-chicago-taxi-trips-dataset:
-    executorLabel: exec-chicago-taxi-trips-dataset
-    inputDefinitions:
-      parameters:
-        format:
-          defaultValue: csv
-          isOptional: true
-          parameterType: STRING
-        limit:
-          defaultValue: 1000.0
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-        select:
-          defaultValue: trip_id,taxi_id,trip_start_timestamp,trip_end_timestamp,trip_seconds,trip_miles,pickup_census_tract,dropoff_census_tract,pickup_community_area,dropoff_community_area,fare,tips,tolls,extras,trip_total,payment_type,company,pickup_centroid_latitude,pickup_centroid_longitude,pickup_centroid_location,dropoff_centroid_latitude,dropoff_centroid_longitude,dropoff_centroid_location
-          isOptional: true
-          parameterType: STRING
-        where:
-          defaultValue: trip_start_timestamp>="1900-01-01" AND trip_start_timestamp<"2100-01-01"
-          isOptional: true
-          parameterType: STRING
-    outputDefinitions:
-      artifacts:
-        table:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-convert-csv-to-apache-parquet:
-    executorLabel: exec-convert-csv-to-apache-parquet
-    inputDefinitions:
-      artifacts:
-        data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-    outputDefinitions:
-      artifacts:
-        output_data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-xgboost-predict:
-    executorLabel: exec-xgboost-predict
-    inputDefinitions:
-      artifacts:
-        data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-        model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-      parameters:
-        label_column:
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-    outputDefinitions:
-      artifacts:
-        predictions:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-xgboost-predict-2:
-    executorLabel: exec-xgboost-predict-2
-    inputDefinitions:
-      artifacts:
-        data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-        model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-      parameters:
-        label_column_name:
-          isOptional: true
-          parameterType: STRING
-    outputDefinitions:
-      artifacts:
-        predictions:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-xgboost-predict-3:
-    executorLabel: exec-xgboost-predict-3
-    inputDefinitions:
-      artifacts:
-        data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-        model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-      parameters:
-        label_column_name:
-          isOptional: true
-          parameterType: STRING
-    outputDefinitions:
-      artifacts:
-        predictions:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-xgboost-predict-4:
-    executorLabel: exec-xgboost-predict-4
-    inputDefinitions:
-      artifacts:
-        data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-        model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-      parameters:
-        label_column:
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-    outputDefinitions:
-      artifacts:
-        predictions:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-xgboost-train:
-    executorLabel: exec-xgboost-train
-    inputDefinitions:
-      artifacts:
-        starting_model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-          isOptional: true
-        training_data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-      parameters:
-        booster:
-          defaultValue: gbtree
-          isOptional: true
-          parameterType: STRING
-        booster_params:
-          isOptional: true
-          parameterType: STRUCT
-        label_column:
-          defaultValue: 0.0
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-        learning_rate:
-          defaultValue: 0.3
-          isOptional: true
-          parameterType: NUMBER_DOUBLE
-        max_depth:
-          defaultValue: 6.0
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-        min_split_loss:
-          defaultValue: 0.0
-          isOptional: true
-          parameterType: NUMBER_DOUBLE
-        num_iterations:
-          defaultValue: 10.0
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-        objective:
-          defaultValue: reg:squarederror
-          isOptional: true
-          parameterType: STRING
-    outputDefinitions:
-      artifacts:
-        model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-        model_config:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-  comp-xgboost-train-2:
-    executorLabel: exec-xgboost-train-2
-    inputDefinitions:
-      artifacts:
-        starting_model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-          isOptional: true
-        training_data:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-      parameters:
-        booster:
-          defaultValue: gbtree
-          isOptional: true
-          parameterType: STRING
-        booster_params:
-          isOptional: true
-          parameterType: STRUCT
-        label_column_name:
-          parameterType: STRING
-        learning_rate:
-          defaultValue: 0.3
-          isOptional: true
-          parameterType: NUMBER_DOUBLE
-        max_depth:
-          defaultValue: 6.0
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-        min_split_loss:
-          defaultValue: 0.0
-          isOptional: true
-          parameterType: NUMBER_DOUBLE
-        num_iterations:
-          defaultValue: 10.0
-          isOptional: true
-          parameterType: NUMBER_INTEGER
-        objective:
-          defaultValue: reg:squarederror
-          isOptional: true
-          parameterType: STRING
-    outputDefinitions:
-      artifacts:
-        model:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-        model_config:
-          artifactType:
-            schemaTitle: system.Artifact
-            schemaVersion: 0.0.1
-deploymentSpec:
-  executors:
-    exec-chicago-taxi-trips-dataset:
-      container:
-        command:
-        - sh
-        - -c
-        - "set -e -x -o pipefail\noutput_path=\"$0\"\nselect=\"$1\"\nwhere=\"$2\"\n\
-          limit=\"$3\"\nformat=\"$4\"\nmkdir -p \"$(dirname \"$output_path\")\"\n\
-          curl --get 'https://data.cityofchicago.org/resource/wrvz-psew.'\"${format}\"\
-          \ \\\n    --data-urlencode '$limit='\"${limit}\" \\\n    --data-urlencode\
-          \ '$where='\"${where}\" \\\n    --data-urlencode '$select='\"${select}\"\
-          \ \\\n    | tr -d '\"' > \"$output_path\"  # Removing unneeded quotes around\
-          \ all numbers\n"
-        - '{{$.outputs.artifacts[''table''].path}}'
-        - '{{$.inputs.parameters[''select'']}}'
-        - '{{$.inputs.parameters[''where'']}}'
-        - '{{$.inputs.parameters[''limit'']}}'
-        - '{{$.inputs.parameters[''format'']}}'
-        image: byrnedo/alpine-curl@sha256:548379d0a4a0c08b9e55d9d87a592b7d35d9ab3037f4936f5ccd09d0b625a342
-    exec-convert-csv-to-apache-parquet:
-      container:
-        args:
-        - --data
-        - '{{$.inputs.artifacts[''data''].path}}'
-        - --output-data
-        - '{{$.outputs.artifacts[''output_data''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'pyarrow==0.17.1' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install
-          --quiet --no-warn-script-location 'pyarrow==0.17.1' --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef convert_csv_to_apache_parquet(\n    data_path,\n    output_data_path,\n\
-          ):\n    '''Converts CSV table to Apache Parquet.\n\n    [Apache Parquet](https://parquet.apache.org/)\n\
-          \n    Annotations:\n        author: Alexey Volkov \n\
-          \    '''\n    from pyarrow import csv, parquet\n\n    table = csv.read_csv(data_path)\n\
-          \    parquet.write_table(table, output_data_path)\n\nimport argparse\n_parser\
-          \ = argparse.ArgumentParser(prog='Convert csv to apache parquet', description='Converts\
-          \ CSV table to Apache Parquet.\\n\\n    [Apache Parquet](https://parquet.apache.org/)\\\
-          n\\n    Annotations:\\n        author: Alexey Volkov ')\n\
-          _parser.add_argument(\"--data\", dest=\"data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--output-data\", dest=\"\
-          output_data_path\", type=_make_parent_dirs_and_return_path, required=True,\
-          \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          _output_files = _parsed_args.pop(\"_output_paths\", [])\n\n_outputs = convert_csv_to_apache_parquet(**_parsed_args)\n\
-          \n_output_serializers = [\n\n]\n\nimport os\nfor idx, output_file in enumerate(_output_files):\n\
-          \    try:\n        os.makedirs(os.path.dirname(output_file))\n    except\
-          \ OSError:\n        pass\n    with open(output_file, 'w') as f:\n      \
-          \  f.write(_output_serializers[idx](_outputs[idx]))\n"
-        image: python:3.7
-    exec-xgboost-predict:
-      container:
-        args:
-        - --data
-        - '{{$.inputs.artifacts[''data''].path}}'
-        - --model
-        - '{{$.inputs.artifacts[''model''].path}}'
-        - '{"IfPresent": {"InputName": "label_column", "Then": ["--label-column",
-          "{{$.inputs.parameters[''label_column'']}}"]}}'
-        - --predictions
-        - '{{$.outputs.artifacts[''predictions''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'xgboost==1.1.1' 'pandas==1.0.5' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
-          -m pip install --quiet --no-warn-script-location 'xgboost==1.1.1' 'pandas==1.0.5'
-          --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef xgboost_predict(\n    data_path,  # Also supports LibSVM\n\
-          \    model_path,\n    predictions_path,\n    label_column = None,\n):\n\
-          \    '''Make predictions using a trained XGBoost model.\n\n    Args:\n \
-          \       data_path: Path for the feature data in CSV format.\n        model_path:\
-          \ Path for the trained model in binary XGBoost format.\n        predictions_path:\
-          \ Output path for the predictions.\n        label_column: Column containing\
-          \ the label data.\n\n    Annotations:\n        author: Alexey Volkov \n\
-          \    '''\n    from pathlib import Path\n\n    import numpy\n    import pandas\n\
-          \    import xgboost\n\n    df = pandas.read_csv(\n        data_path,\n \
-          \   )\n\n    if label_column is not None:\n        df = df.drop(columns=[df.columns[label_column]])\n\
-          \n    testing_data = xgboost.DMatrix(\n        data=df,\n    )\n\n    model\
-          \ = xgboost.Booster(model_file=model_path)\n\n    predictions = model.predict(testing_data)\n\
-          \n    Path(predictions_path).parent.mkdir(parents=True, exist_ok=True)\n\
-          \    numpy.savetxt(predictions_path, predictions)\n\nimport argparse\n_parser\
-          \ = argparse.ArgumentParser(prog='Xgboost predict', description='Make predictions\
-          \ using a trained XGBoost model.\\n\\n    Args:\\n        data_path: Path\
-          \ for the feature data in CSV format.\\n        model_path: Path for the\
-          \ trained model in binary XGBoost format.\\n        predictions_path: Output\
-          \ path for the predictions.\\n        label_column: Column containing the\
-          \ label data.\\n\\n    Annotations:\\n        author: Alexey Volkov ')\n\
-          _parser.add_argument(\"--data\", dest=\"data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--model\", dest=\"\
-          model_path\", type=str, required=True, default=argparse.SUPPRESS)\n_parser.add_argument(\"\
-          --label-column\", dest=\"label_column\", type=int, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--predictions\", dest=\"predictions_path\", type=_make_parent_dirs_and_return_path,\
-          \ required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
-    exec-xgboost-predict-2:
-      container:
-        args:
-        - --data
-        - '{{$.inputs.artifacts[''data''].path}}'
-        - --model
-        - '{{$.inputs.artifacts[''model''].path}}'
-        - '{"IfPresent": {"InputName": "label_column_name", "Then": ["--label-column-name",
-          "{{$.inputs.parameters[''label_column_name'']}}"]}}'
-        - --predictions
-        - '{{$.outputs.artifacts[''predictions''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'xgboost==1.1.1' 'pandas==1.0.5' 'pyarrow==0.17.1' || PIP_DISABLE_PIP_VERSION_CHECK=1
-          python3 -m pip install --quiet --no-warn-script-location 'xgboost==1.1.1'
-          'pandas==1.0.5' 'pyarrow==0.17.1' --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef xgboost_predict(\n    data_path,\n    model_path,\n \
-          \   predictions_path,\n    label_column_name = None,\n):\n    '''Make predictions\
-          \ using a trained XGBoost model.\n\n    Args:\n        data_path: Path for\
-          \ the feature data in Apache Parquet format.\n        model_path: Path for\
-          \ the trained model in binary XGBoost format.\n        predictions_path:\
-          \ Output path for the predictions.\n        label_column_name: Optional.\
-          \ Name of the column containing the label data that is excluded during the\
-          \ prediction.\n\n    Annotations:\n        author: Alexey Volkov \n\
-          \    '''\n    from pathlib import Path\n\n    import numpy\n    import pandas\n\
-          \    import xgboost\n\n    # Loading data\n    df = pandas.read_parquet(data_path)\n\
-          \    if label_column_name:\n        df = df.drop(columns=[label_column_name])\n\
-          \n    evaluation_data = xgboost.DMatrix(\n        data=df,\n    )\n\n  \
-          \  # Training\n    model = xgboost.Booster(model_file=model_path)\n\n  \
-          \  predictions = model.predict(evaluation_data)\n\n    Path(predictions_path).parent.mkdir(parents=True,\
-          \ exist_ok=True)\n    numpy.savetxt(predictions_path, predictions)\n\nimport\
-          \ argparse\n_parser = argparse.ArgumentParser(prog='Xgboost predict', description='Make\
-          \ predictions using a trained XGBoost model.\\n\\n    Args:\\n        data_path:\
-          \ Path for the feature data in Apache Parquet format.\\n        model_path:\
-          \ Path for the trained model in binary XGBoost format.\\n        predictions_path:\
-          \ Output path for the predictions.\\n        label_column_name: Optional.\
-          \ Name of the column containing the label data that is excluded during the\
-          \ prediction.\\n\\n    Annotations:\\n        author: Alexey Volkov ')\n\
-          _parser.add_argument(\"--data\", dest=\"data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--model\", dest=\"\
-          model_path\", type=str, required=True, default=argparse.SUPPRESS)\n_parser.add_argument(\"\
-          --label-column-name\", dest=\"label_column_name\", type=str, required=False,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--predictions\", dest=\"\
-          predictions_path\", type=_make_parent_dirs_and_return_path, required=True,\
-          \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
-    exec-xgboost-predict-3:
-      container:
-        args:
-        - --data
-        - '{{$.inputs.artifacts[''data''].path}}'
-        - --model
-        - '{{$.inputs.artifacts[''model''].path}}'
-        - '{"IfPresent": {"InputName": "label_column_name", "Then": ["--label-column-name",
-          "{{$.inputs.parameters[''label_column_name'']}}"]}}'
-        - --predictions
-        - '{{$.outputs.artifacts[''predictions''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'xgboost==1.1.1' 'pandas==1.0.5' 'pyarrow==0.17.1' || PIP_DISABLE_PIP_VERSION_CHECK=1
-          python3 -m pip install --quiet --no-warn-script-location 'xgboost==1.1.1'
-          'pandas==1.0.5' 'pyarrow==0.17.1' --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef xgboost_predict(\n    data_path,\n    model_path,\n \
-          \   predictions_path,\n    label_column_name = None,\n):\n    '''Make predictions\
-          \ using a trained XGBoost model.\n\n    Args:\n        data_path: Path for\
-          \ the feature data in Apache Parquet format.\n        model_path: Path for\
-          \ the trained model in binary XGBoost format.\n        predictions_path:\
-          \ Output path for the predictions.\n        label_column_name: Optional.\
-          \ Name of the column containing the label data that is excluded during the\
-          \ prediction.\n\n    Annotations:\n        author: Alexey Volkov \n\
-          \    '''\n    from pathlib import Path\n\n    import numpy\n    import pandas\n\
-          \    import xgboost\n\n    # Loading data\n    df = pandas.read_parquet(data_path)\n\
-          \    if label_column_name:\n        df = df.drop(columns=[label_column_name])\n\
-          \n    evaluation_data = xgboost.DMatrix(\n        data=df,\n    )\n\n  \
-          \  # Training\n    model = xgboost.Booster(model_file=model_path)\n\n  \
-          \  predictions = model.predict(evaluation_data)\n\n    Path(predictions_path).parent.mkdir(parents=True,\
-          \ exist_ok=True)\n    numpy.savetxt(predictions_path, predictions)\n\nimport\
-          \ argparse\n_parser = argparse.ArgumentParser(prog='Xgboost predict', description='Make\
-          \ predictions using a trained XGBoost model.\\n\\n    Args:\\n        data_path:\
-          \ Path for the feature data in Apache Parquet format.\\n        model_path:\
-          \ Path for the trained model in binary XGBoost format.\\n        predictions_path:\
-          \ Output path for the predictions.\\n        label_column_name: Optional.\
-          \ Name of the column containing the label data that is excluded during the\
-          \ prediction.\\n\\n    Annotations:\\n        author: Alexey Volkov ')\n\
-          _parser.add_argument(\"--data\", dest=\"data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--model\", dest=\"\
-          model_path\", type=str, required=True, default=argparse.SUPPRESS)\n_parser.add_argument(\"\
-          --label-column-name\", dest=\"label_column_name\", type=str, required=False,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--predictions\", dest=\"\
-          predictions_path\", type=_make_parent_dirs_and_return_path, required=True,\
-          \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
-    exec-xgboost-predict-4:
-      container:
-        args:
-        - --data
-        - '{{$.inputs.artifacts[''data''].path}}'
-        - --model
-        - '{{$.inputs.artifacts[''model''].path}}'
-        - '{"IfPresent": {"InputName": "label_column", "Then": ["--label-column",
-          "{{$.inputs.parameters[''label_column'']}}"]}}'
-        - --predictions
-        - '{{$.outputs.artifacts[''predictions''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'xgboost==1.1.1' 'pandas==1.0.5' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
-          -m pip install --quiet --no-warn-script-location 'xgboost==1.1.1' 'pandas==1.0.5'
-          --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef xgboost_predict(\n    data_path,  # Also supports LibSVM\n\
-          \    model_path,\n    predictions_path,\n    label_column = None,\n):\n\
-          \    '''Make predictions using a trained XGBoost model.\n\n    Args:\n \
-          \       data_path: Path for the feature data in CSV format.\n        model_path:\
-          \ Path for the trained model in binary XGBoost format.\n        predictions_path:\
-          \ Output path for the predictions.\n        label_column: Column containing\
-          \ the label data.\n\n    Annotations:\n        author: Alexey Volkov \n\
-          \    '''\n    from pathlib import Path\n\n    import numpy\n    import pandas\n\
-          \    import xgboost\n\n    df = pandas.read_csv(\n        data_path,\n \
-          \   )\n\n    if label_column is not None:\n        df = df.drop(columns=[df.columns[label_column]])\n\
-          \n    testing_data = xgboost.DMatrix(\n        data=df,\n    )\n\n    model\
-          \ = xgboost.Booster(model_file=model_path)\n\n    predictions = model.predict(testing_data)\n\
-          \n    Path(predictions_path).parent.mkdir(parents=True, exist_ok=True)\n\
-          \    numpy.savetxt(predictions_path, predictions)\n\nimport argparse\n_parser\
-          \ = argparse.ArgumentParser(prog='Xgboost predict', description='Make predictions\
-          \ using a trained XGBoost model.\\n\\n    Args:\\n        data_path: Path\
-          \ for the feature data in CSV format.\\n        model_path: Path for the\
-          \ trained model in binary XGBoost format.\\n        predictions_path: Output\
-          \ path for the predictions.\\n        label_column: Column containing the\
-          \ label data.\\n\\n    Annotations:\\n        author: Alexey Volkov ')\n\
-          _parser.add_argument(\"--data\", dest=\"data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--model\", dest=\"\
-          model_path\", type=str, required=True, default=argparse.SUPPRESS)\n_parser.add_argument(\"\
-          --label-column\", dest=\"label_column\", type=int, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--predictions\", dest=\"predictions_path\", type=_make_parent_dirs_and_return_path,\
-          \ required=True, default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          \n_outputs = xgboost_predict(**_parsed_args)\n"
-        image: python:3.7
-    exec-xgboost-train:
-      container:
-        args:
-        - --training-data
-        - '{{$.inputs.artifacts[''training_data''].path}}'
-        - '{"IfPresent": {"InputName": "starting_model", "Then": ["--starting-model",
-          "{{$.inputs.artifacts[''starting_model''].path}}"]}}'
-        - '{"IfPresent": {"InputName": "label_column", "Then": ["--label-column",
-          "{{$.inputs.parameters[''label_column'']}}"]}}'
-        - '{"IfPresent": {"InputName": "num_iterations", "Then": ["--num-iterations",
-          "{{$.inputs.parameters[''num_iterations'']}}"]}}'
-        - '{"IfPresent": {"InputName": "booster_params", "Then": ["--booster-params",
-          "{{$.inputs.parameters[''booster_params'']}}"]}}'
-        - '{"IfPresent": {"InputName": "objective", "Then": ["--objective", "{{$.inputs.parameters[''objective'']}}"]}}'
-        - '{"IfPresent": {"InputName": "booster", "Then": ["--booster", "{{$.inputs.parameters[''booster'']}}"]}}'
-        - '{"IfPresent": {"InputName": "learning_rate", "Then": ["--learning-rate",
-          "{{$.inputs.parameters[''learning_rate'']}}"]}}'
-        - '{"IfPresent": {"InputName": "min_split_loss", "Then": ["--min-split-loss",
-          "{{$.inputs.parameters[''min_split_loss'']}}"]}}'
-        - '{"IfPresent": {"InputName": "max_depth", "Then": ["--max-depth", "{{$.inputs.parameters[''max_depth'']}}"]}}'
-        - --model
-        - '{{$.outputs.artifacts[''model''].path}}'
-        - --model-config
-        - '{{$.outputs.artifacts[''model_config''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'xgboost==1.1.1' 'pandas==1.0.5' || PIP_DISABLE_PIP_VERSION_CHECK=1 python3
-          -m pip install --quiet --no-warn-script-location 'xgboost==1.1.1' 'pandas==1.0.5'
-          --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef xgboost_train(\n    training_data_path,  # Also supports\
-          \ LibSVM\n    model_path,\n    model_config_path,\n    starting_model_path\
-          \ = None,\n\n    label_column = 0,\n    num_iterations = 10,\n    booster_params\
-          \ = None,\n\n    # Booster parameters\n    objective = 'reg:squarederror',\n\
-          \    booster = 'gbtree',\n    learning_rate = 0.3,\n    min_split_loss =\
-          \ 0,\n    max_depth = 6,\n):\n    '''Train an XGBoost model.\n\n    Args:\n\
-          \        training_data_path: Path for the training data in CSV format.\n\
-          \        model_path: Output path for the trained model in binary XGBoost\
-          \ format.\n        model_config_path: Output path for the internal parameter\
-          \ configuration of Booster as a JSON string.\n        starting_model_path:\
-          \ Path for the existing trained model to start from.\n        label_column:\
-          \ Column containing the label data.\n        num_boost_rounds: Number of\
-          \ boosting iterations.\n        booster_params: Parameters for the booster.\
-          \ See https://xgboost.readthedocs.io/en/latest/parameter.html\n        objective:\
-          \ The learning task and the corresponding learning objective.\n        \
-          \    See https://xgboost.readthedocs.io/en/latest/parameter.html#learning-task-parameters\n\
-          \            The most common values are:\n            \"reg:squarederror\"\
-          \ - Regression with squared loss (default).\n            \"reg:logistic\"\
-          \ - Logistic regression.\n            \"binary:logistic\" - Logistic regression\
-          \ for binary classification, output probability.\n            \"binary:logitraw\"\
-          \ - Logistic regression for binary classification, output score before logistic\
-          \ transformation\n            \"rank:pairwise\" - Use LambdaMART to perform\
-          \ pairwise ranking where the pairwise loss is minimized\n            \"\
-          rank:ndcg\" - Use LambdaMART to perform list-wise ranking where Normalized\
-          \ Discounted Cumulative Gain (NDCG) is maximized\n\n    Annotations:\n \
-          \       author: Alexey Volkov \n    '''\n   \
-          \ import pandas\n    import xgboost\n\n    df = pandas.read_csv(\n     \
-          \   training_data_path,\n    )\n\n    training_data = xgboost.DMatrix(\n\
-          \        data=df.drop(columns=[df.columns[label_column]]),\n        label=df[df.columns[label_column]],\n\
-          \    )\n\n    booster_params = booster_params or {}\n    booster_params.setdefault('objective',\
-          \ objective)\n    booster_params.setdefault('booster', booster)\n    booster_params.setdefault('learning_rate',\
-          \ learning_rate)\n    booster_params.setdefault('min_split_loss', min_split_loss)\n\
-          \    booster_params.setdefault('max_depth', max_depth)\n\n    starting_model\
-          \ = None\n    if starting_model_path:\n        starting_model = xgboost.Booster(model_file=starting_model_path)\n\
-          \n    model = xgboost.train(\n        params=booster_params,\n        dtrain=training_data,\n\
-          \        num_boost_round=num_iterations,\n        xgb_model=starting_model\n\
-          \    )\n\n    # Saving the model in binary format\n    model.save_model(model_path)\n\
-          \n    model_config_str = model.save_config()\n    with open(model_config_path,\
-          \ 'w') as model_config_file:\n        model_config_file.write(model_config_str)\n\
-          \nimport json\nimport argparse\n_parser = argparse.ArgumentParser(prog='Xgboost\
-          \ train', description='Train an XGBoost model.\\n\\n    Args:\\n       \
-          \ training_data_path: Path for the training data in CSV format.\\n     \
-          \   model_path: Output path for the trained model in binary XGBoost format.\\\
-          n        model_config_path: Output path for the internal parameter configuration\
-          \ of Booster as a JSON string.\\n        starting_model_path: Path for the\
-          \ existing trained model to start from.\\n        label_column: Column containing\
-          \ the label data.\\n        num_boost_rounds: Number of boosting iterations.\\\
-          n        booster_params: Parameters for the booster. See https://xgboost.readthedocs.io/en/latest/parameter.html\\\
-          n        objective: The learning task and the corresponding learning objective.\\\
-          n            See https://xgboost.readthedocs.io/en/latest/parameter.html#learning-task-parameters\\\
-          n            The most common values are:\\n            \"reg:squarederror\"\
-          \ - Regression with squared loss (default).\\n            \"reg:logistic\"\
-          \ - Logistic regression.\\n            \"binary:logistic\" - Logistic regression\
-          \ for binary classification, output probability.\\n            \"binary:logitraw\"\
-          \ - Logistic regression for binary classification, output score before logistic\
-          \ transformation\\n            \"rank:pairwise\" - Use LambdaMART to perform\
-          \ pairwise ranking where the pairwise loss is minimized\\n            \"\
-          rank:ndcg\" - Use LambdaMART to perform list-wise ranking where Normalized\
-          \ Discounted Cumulative Gain (NDCG) is maximized\\n\\n    Annotations:\\\
-          n        author: Alexey Volkov ')\n_parser.add_argument(\"\
-          --training-data\", dest=\"training_data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--starting-model\"\
-          , dest=\"starting_model_path\", type=str, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--label-column\", dest=\"label_column\", type=int,\
-          \ required=False, default=argparse.SUPPRESS)\n_parser.add_argument(\"--num-iterations\"\
-          , dest=\"num_iterations\", type=int, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--booster-params\", dest=\"booster_params\", type=json.loads,\
-          \ required=False, default=argparse.SUPPRESS)\n_parser.add_argument(\"--objective\"\
-          , dest=\"objective\", type=str, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--booster\", dest=\"booster\", type=str, required=False,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--learning-rate\",\
-          \ dest=\"learning_rate\", type=float, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--min-split-loss\", dest=\"min_split_loss\", type=float,\
-          \ required=False, default=argparse.SUPPRESS)\n_parser.add_argument(\"--max-depth\"\
-          , dest=\"max_depth\", type=int, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--model\", dest=\"model_path\", type=_make_parent_dirs_and_return_path,\
-          \ required=True, default=argparse.SUPPRESS)\n_parser.add_argument(\"--model-config\"\
-          , dest=\"model_config_path\", type=_make_parent_dirs_and_return_path, required=True,\
-          \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          \n_outputs = xgboost_train(**_parsed_args)\n"
-        image: python:3.7
-    exec-xgboost-train-2:
-      container:
-        args:
-        - --training-data
-        - '{{$.inputs.artifacts[''training_data''].path}}'
-        - --label-column-name
-        - '{{$.inputs.parameters[''label_column_name'']}}'
-        - '{"IfPresent": {"InputName": "starting_model", "Then": ["--starting-model",
-          "{{$.inputs.artifacts[''starting_model''].path}}"]}}'
-        - '{"IfPresent": {"InputName": "num_iterations", "Then": ["--num-iterations",
-          "{{$.inputs.parameters[''num_iterations'']}}"]}}'
-        - '{"IfPresent": {"InputName": "booster_params", "Then": ["--booster-params",
-          "{{$.inputs.parameters[''booster_params'']}}"]}}'
-        - '{"IfPresent": {"InputName": "objective", "Then": ["--objective", "{{$.inputs.parameters[''objective'']}}"]}}'
-        - '{"IfPresent": {"InputName": "booster", "Then": ["--booster", "{{$.inputs.parameters[''booster'']}}"]}}'
-        - '{"IfPresent": {"InputName": "learning_rate", "Then": ["--learning-rate",
-          "{{$.inputs.parameters[''learning_rate'']}}"]}}'
-        - '{"IfPresent": {"InputName": "min_split_loss", "Then": ["--min-split-loss",
-          "{{$.inputs.parameters[''min_split_loss'']}}"]}}'
-        - '{"IfPresent": {"InputName": "max_depth", "Then": ["--max-depth", "{{$.inputs.parameters[''max_depth'']}}"]}}'
-        - --model
-        - '{{$.outputs.artifacts[''model''].path}}'
-        - --model-config
-        - '{{$.outputs.artifacts[''model_config''].path}}'
-        command:
-        - sh
-        - -c
-        - (PIP_DISABLE_PIP_VERSION_CHECK=1 python3 -m pip install --quiet --no-warn-script-location
-          'xgboost==1.1.1' 'pandas==1.0.5' 'pyarrow==0.17.1' || PIP_DISABLE_PIP_VERSION_CHECK=1
-          python3 -m pip install --quiet --no-warn-script-location 'xgboost==1.1.1'
-          'pandas==1.0.5' 'pyarrow==0.17.1' --user) && "$0" "$@"
-        - python3
-        - -u
-        - -c
-        - "def _make_parent_dirs_and_return_path(file_path: str):\n    import os\n\
-          \    os.makedirs(os.path.dirname(file_path), exist_ok=True)\n    return\
-          \ file_path\n\ndef xgboost_train(\n    training_data_path,\n    model_path,\n\
-          \    model_config_path,\n    label_column_name,\n\n    starting_model_path\
-          \ = None,\n\n    num_iterations = 10,\n    booster_params = None,\n\n  \
-          \  # Booster parameters\n    objective = 'reg:squarederror',\n    booster\
-          \ = 'gbtree',\n    learning_rate = 0.3,\n    min_split_loss = 0,\n    max_depth\
-          \ = 6,\n):\n    '''Train an XGBoost model.\n\n    Args:\n        training_data_path:\
-          \ Path for the training data in Apache Parquet format.\n        model_path:\
-          \ Output path for the trained model in binary XGBoost format.\n        model_config_path:\
-          \ Output path for the internal parameter configuration of Booster as a JSON\
-          \ string.\n        starting_model_path: Path for the existing trained model\
-          \ to start from.\n        label_column_name: Name of the column containing\
-          \ the label data.\n        num_boost_rounds: Number of boosting iterations.\n\
-          \        booster_params: Parameters for the booster. See https://xgboost.readthedocs.io/en/latest/parameter.html\n\
-          \        objective: The learning task and the corresponding learning objective.\n\
-          \            See https://xgboost.readthedocs.io/en/latest/parameter.html#learning-task-parameters\n\
-          \            The most common values are:\n            \"reg:squarederror\"\
-          \ - Regression with squared loss (default).\n            \"reg:logistic\"\
-          \ - Logistic regression.\n            \"binary:logistic\" - Logistic regression\
-          \ for binary classification, output probability.\n            \"binary:logitraw\"\
-          \ - Logistic regression for binary classification, output score before logistic\
-          \ transformation\n            \"rank:pairwise\" - Use LambdaMART to perform\
-          \ pairwise ranking where the pairwise loss is minimized\n            \"\
-          rank:ndcg\" - Use LambdaMART to perform list-wise ranking where Normalized\
-          \ Discounted Cumulative Gain (NDCG) is maximized\n\n    Annotations:\n \
-          \       author: Alexey Volkov \n    '''\n   \
-          \ import pandas\n    import xgboost\n\n    # Loading data\n    df = pandas.read_parquet(training_data_path)\n\
-          \    training_data = xgboost.DMatrix(\n        data=df.drop(columns=[label_column_name]),\n\
-          \        label=df[[label_column_name]],\n    )\n    # Training\n    booster_params\
-          \ = booster_params or {}\n    booster_params.setdefault('objective', objective)\n\
-          \    booster_params.setdefault('booster', booster)\n    booster_params.setdefault('learning_rate',\
-          \ learning_rate)\n    booster_params.setdefault('min_split_loss', min_split_loss)\n\
-          \    booster_params.setdefault('max_depth', max_depth)\n\n    starting_model\
-          \ = None\n    if starting_model_path:\n        starting_model = xgboost.Booster(model_file=starting_model_path)\n\
-          \n    model = xgboost.train(\n        params=booster_params,\n        dtrain=training_data,\n\
-          \        num_boost_round=num_iterations,\n        xgb_model=starting_model\n\
-          \    )\n\n    # Saving the model in binary format\n    model.save_model(model_path)\n\
-          \n    model_config_str = model.save_config()\n    with open(model_config_path,\
-          \ 'w') as model_config_file:\n        model_config_file.write(model_config_str)\n\
-          \nimport json\nimport argparse\n_parser = argparse.ArgumentParser(prog='Xgboost\
-          \ train', description='Train an XGBoost model.\\n\\n    Args:\\n       \
-          \ training_data_path: Path for the training data in Apache Parquet format.\\\
-          n        model_path: Output path for the trained model in binary XGBoost\
-          \ format.\\n        model_config_path: Output path for the internal parameter\
-          \ configuration of Booster as a JSON string.\\n        starting_model_path:\
-          \ Path for the existing trained model to start from.\\n        label_column_name:\
-          \ Name of the column containing the label data.\\n        num_boost_rounds:\
-          \ Number of boosting iterations.\\n        booster_params: Parameters for\
-          \ the booster. See https://xgboost.readthedocs.io/en/latest/parameter.html\\\
-          n        objective: The learning task and the corresponding learning objective.\\\
-          n            See https://xgboost.readthedocs.io/en/latest/parameter.html#learning-task-parameters\\\
-          n            The most common values are:\\n            \"reg:squarederror\"\
-          \ - Regression with squared loss (default).\\n            \"reg:logistic\"\
-          \ - Logistic regression.\\n            \"binary:logistic\" - Logistic regression\
-          \ for binary classification, output probability.\\n            \"binary:logitraw\"\
-          \ - Logistic regression for binary classification, output score before logistic\
-          \ transformation\\n            \"rank:pairwise\" - Use LambdaMART to perform\
-          \ pairwise ranking where the pairwise loss is minimized\\n            \"\
-          rank:ndcg\" - Use LambdaMART to perform list-wise ranking where Normalized\
-          \ Discounted Cumulative Gain (NDCG) is maximized\\n\\n    Annotations:\\\
-          n        author: Alexey Volkov ')\n_parser.add_argument(\"\
-          --training-data\", dest=\"training_data_path\", type=str, required=True,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--label-column-name\"\
-          , dest=\"label_column_name\", type=str, required=True, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--starting-model\", dest=\"starting_model_path\"\
-          , type=str, required=False, default=argparse.SUPPRESS)\n_parser.add_argument(\"\
-          --num-iterations\", dest=\"num_iterations\", type=int, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--booster-params\", dest=\"booster_params\", type=json.loads,\
-          \ required=False, default=argparse.SUPPRESS)\n_parser.add_argument(\"--objective\"\
-          , dest=\"objective\", type=str, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--booster\", dest=\"booster\", type=str, required=False,\
-          \ default=argparse.SUPPRESS)\n_parser.add_argument(\"--learning-rate\",\
-          \ dest=\"learning_rate\", type=float, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--min-split-loss\", dest=\"min_split_loss\", type=float,\
-          \ required=False, default=argparse.SUPPRESS)\n_parser.add_argument(\"--max-depth\"\
-          , dest=\"max_depth\", type=int, required=False, default=argparse.SUPPRESS)\n\
-          _parser.add_argument(\"--model\", dest=\"model_path\", type=_make_parent_dirs_and_return_path,\
-          \ required=True, default=argparse.SUPPRESS)\n_parser.add_argument(\"--model-config\"\
-          , dest=\"model_config_path\", type=_make_parent_dirs_and_return_path, required=True,\
-          \ default=argparse.SUPPRESS)\n_parsed_args = vars(_parser.parse_args())\n\
-          \n_outputs = xgboost_train(**_parsed_args)\n"
-        image: python:3.7
-pipelineInfo:
-  name: xgboost-sample-pipeline
-root:
-  dag:
-    tasks:
-      chicago-taxi-trips-dataset:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-chicago-taxi-trips-dataset
-        inputs:
-          parameters:
-            limit:
-              runtimeValue:
-                constant: 10000.0
-            select:
-              runtimeValue:
-                constant: tips,trip_seconds,trip_miles,pickup_community_area,dropoff_community_area,fare,tolls,extras,trip_total
-            where:
-              runtimeValue:
-                constant: trip_start_timestamp >= "2019-01-01" AND trip_start_timestamp
-                  < "2019-02-01"
-        taskInfo:
-          name: chicago-taxi-trips-dataset
-      convert-csv-to-apache-parquet:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-convert-csv-to-apache-parquet
-        dependentTasks:
-        - chicago-taxi-trips-dataset
-        inputs:
-          artifacts:
-            data:
-              taskOutputArtifact:
-                outputArtifactKey: table
-                producerTask: chicago-taxi-trips-dataset
-        taskInfo:
-          name: convert-csv-to-apache-parquet
-      xgboost-predict:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-xgboost-predict
-        dependentTasks:
-        - chicago-taxi-trips-dataset
-        - xgboost-train
-        inputs:
-          artifacts:
-            data:
-              taskOutputArtifact:
-                outputArtifactKey: table
-                producerTask: chicago-taxi-trips-dataset
-            model:
-              taskOutputArtifact:
-                outputArtifactKey: model
-                producerTask: xgboost-train
-          parameters:
-            label_column:
-              runtimeValue:
-                constant: 0.0
-        taskInfo:
-          name: xgboost-predict
-      xgboost-predict-2:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-xgboost-predict-2
-        dependentTasks:
-        - convert-csv-to-apache-parquet
-        - xgboost-train-2
-        inputs:
-          artifacts:
-            data:
-              taskOutputArtifact:
-                outputArtifactKey: output_data
-                producerTask: convert-csv-to-apache-parquet
-            model:
-              taskOutputArtifact:
-                outputArtifactKey: model
-                producerTask: xgboost-train-2
-          parameters:
-            label_column_name:
-              runtimeValue:
-                constant: tips
-        taskInfo:
-          name: xgboost-predict-2
-      xgboost-predict-3:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-xgboost-predict-3
-        dependentTasks:
-        - convert-csv-to-apache-parquet
-        - xgboost-train
-        inputs:
-          artifacts:
-            data:
-              taskOutputArtifact:
-                outputArtifactKey: output_data
-                producerTask: convert-csv-to-apache-parquet
-            model:
-              taskOutputArtifact:
-                outputArtifactKey: model
-                producerTask: xgboost-train
-          parameters:
-            label_column_name:
-              runtimeValue:
-                constant: tips
-        taskInfo:
-          name: xgboost-predict-3
-      xgboost-predict-4:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-xgboost-predict-4
-        dependentTasks:
-        - chicago-taxi-trips-dataset
-        - xgboost-train-2
-        inputs:
-          artifacts:
-            data:
-              taskOutputArtifact:
-                outputArtifactKey: table
-                producerTask: chicago-taxi-trips-dataset
-            model:
-              taskOutputArtifact:
-                outputArtifactKey: model
-                producerTask: xgboost-train-2
-          parameters:
-            label_column:
-              runtimeValue:
-                constant: 0.0
-        taskInfo:
-          name: xgboost-predict-4
-      xgboost-train:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-xgboost-train
-        dependentTasks:
-        - chicago-taxi-trips-dataset
-        inputs:
-          artifacts:
-            training_data:
-              taskOutputArtifact:
-                outputArtifactKey: table
-                producerTask: chicago-taxi-trips-dataset
-          parameters:
-            label_column:
-              runtimeValue:
-                constant: 0.0
-            num_iterations:
-              runtimeValue:
-                constant: 200.0
-            objective:
-              runtimeValue:
-                constant: reg:squarederror
-        taskInfo:
-          name: xgboost-train
-      xgboost-train-2:
-        cachingOptions:
-          enableCache: true
-        componentRef:
-          name: comp-xgboost-train-2
-        dependentTasks:
-        - convert-csv-to-apache-parquet
-        inputs:
-          artifacts:
-            training_data:
-              taskOutputArtifact:
-                outputArtifactKey: output_data
-                producerTask: convert-csv-to-apache-parquet
-          parameters:
-            label_column_name:
-              runtimeValue:
-                constant: tips
-            num_iterations:
-              runtimeValue:
-                constant: 200.0
-            objective:
-              runtimeValue:
-                constant: reg:squarederror
-        taskInfo:
-          name: xgboost-train-2
-schemaVersion: 2.1.0
-sdkVersion: kfp-2.7.0
diff --git a/sdk/python/test_data/test_data_config.yaml b/sdk/python/test_data/test_data_config.yaml
index ddfa0802f533..91aed116dc5d 100644
--- a/sdk/python/test_data/test_data_config.yaml
+++ b/sdk/python/test_data/test_data_config.yaml
@@ -80,9 +80,6 @@ pipelines:
           "first_number": 1,
           "second_number": 2,
         }
-    - module: xgboost_sample_pipeline
-      name: xgboost_pipeline
-      execute: false
     - module: pipeline_with_metrics_outputs
       name: my_pipeline
       execute: true
diff --git a/sdk/python/tests/compiler/testdata/artifact_passing_using_volume.yaml b/sdk/python/tests/compiler/testdata/artifact_passing_using_volume.yaml
index 2a5d433f5db3..837f7bc71bf6 100644
--- a/sdk/python/tests/compiler/testdata/artifact_passing_using_volume.yaml
+++ b/sdk/python/tests/compiler/testdata/artifact_passing_using_volume.yaml
@@ -115,7 +115,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
       volumeMounts:
       - {mountPath: /tmp/outputs/mlpipeline_ui_metadata, name: data-storage, subPath: 'artifact_data/{{workflow.uid}}_{{pod.name}}/mlpipeline-ui-metadata'}
       - {mountPath: /tmp/outputs/mlpipeline_metrics, name: data-storage, subPath: 'artifact_data/{{workflow.uid}}_{{pod.name}}/mlpipeline-metrics'}
@@ -147,7 +147,7 @@ spec:
           = _parsed_args.pop(\"_output_paths\", [])\n\n_outputs = metadata_and_metrics(**_parsed_args)\n\n_output_serializers
           = [\n    str,\n    str,\n\n]\n\nimport os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "name": "Metadata and metrics", "outputs": [{"name":
+          "image": "python:3.9"}}, "name": "Metadata and metrics", "outputs": [{"name":
           "mlpipeline_ui_metadata", "type": "UI_metadata"}, {"name": "mlpipeline_metrics",
           "type": "Metrics"}]}', pipelines.kubeflow.org/component_ref: '{}'}
   - name: processor
diff --git a/sdk/python/tests/compiler/testdata/coin.py b/sdk/python/tests/compiler/testdata/coin.py
index a1f6615217d5..ed0ce24d4fcf 100644
--- a/sdk/python/tests/compiler/testdata/coin.py
+++ b/sdk/python/tests/compiler/testdata/coin.py
@@ -20,7 +20,7 @@ class FlipCoinOp(dsl.ContainerOp):
     def __init__(self, name):
         super(FlipCoinOp, self).__init__(
             name=name,
-            image='python:alpine3.6',
+            image='python:alpine3.9',
             command=['sh', '-c'],
             arguments=[
                 'python -c "import random; result = \'heads\' if random.randint(0,1) == 0 '
@@ -33,7 +33,7 @@ class PrintOp(dsl.ContainerOp):
 
     def __init__(self, name, msg):
         super(PrintOp, self).__init__(
-            name=name, image='alpine:3.6', command=['echo', msg])
+            name=name, image='alpine:3.9', command=['echo', msg])
 
 
 @dsl.pipeline(
diff --git a/sdk/python/tests/compiler/testdata/coin.yaml b/sdk/python/tests/compiler/testdata/coin.yaml
index cef52cb5dae4..9e09d640a0fc 100644
--- a/sdk/python/tests/compiler/testdata/coin.yaml
+++ b/sdk/python/tests/compiler/testdata/coin.yaml
@@ -73,7 +73,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip
     outputs:
       artifacts:
@@ -90,7 +90,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip-again
     outputs:
       artifacts:
@@ -124,7 +124,7 @@ spec:
       command:
       - echo
       - '{{inputs.parameters.flip-again-output}}'
-      image: alpine:3.6
+      image: alpine:3.9
     inputs:
       parameters:
       - name: flip-again-output
@@ -133,7 +133,7 @@ spec:
       command:
       - echo
       - '{{inputs.parameters.flip-again-output}}'
-      image: alpine:3.6
+      image: alpine:3.9
     inputs:
       parameters:
       - name: flip-again-output
diff --git a/sdk/python/tests/compiler/testdata/parallelfor_item_argument_resolving.yaml b/sdk/python/tests/compiler/testdata/parallelfor_item_argument_resolving.yaml
index f9449e73c7cd..09d794fc84fd 100644
--- a/sdk/python/tests/compiler/testdata/parallelfor_item_argument_resolving.yaml
+++ b/sdk/python/tests/compiler/testdata/parallelfor_item_argument_resolving.yaml
@@ -28,7 +28,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-list-of-strings-Output}
@@ -44,7 +44,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-list-of-strings-Output}}"}'}
   - name: consume-2
@@ -67,7 +67,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-list-of-strings-Output-loop-item}
@@ -83,7 +83,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-list-of-strings-Output-loop-item}}"}'}
   - name: consume-3
@@ -106,7 +106,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-str-Output}
@@ -122,7 +122,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-str-Output}}"}'}
   - name: consume-4
@@ -145,7 +145,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-list-of-ints-Output}
@@ -161,7 +161,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-list-of-ints-Output}}"}'}
   - name: consume-5
@@ -184,7 +184,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-list-of-ints-Output-loop-item}
@@ -200,7 +200,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-list-of-ints-Output-loop-item}}"}'}
   - name: consume-6
@@ -223,7 +223,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-list-of-dicts-Output}
@@ -239,7 +239,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-list-of-dicts-Output}}"}'}
   - name: consume-7
@@ -262,7 +262,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: produce-list-of-dicts-Output-loop-item-subvar-aaa}
@@ -278,7 +278,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.produce-list-of-dicts-Output-loop-item-subvar-aaa}}"}'}
   - name: consume-8
@@ -301,7 +301,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     metadata:
       labels:
         pipelines.kubeflow.org/kfp_sdk_version: 1.7.2
@@ -314,7 +314,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "[{\"a\": 1, \"b\": 2}, {\"a\": 10, \"b\": 20}]"}'}
   - name: consume-9
@@ -337,7 +337,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: loop-item-param-4}
@@ -353,7 +353,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.loop-item-param-4}}"}'}
   - name: for-loop-1
@@ -517,7 +517,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
     outputs:
       parameters:
       - name: produce-list-of-dicts-Output
@@ -546,7 +546,7 @@ spec:
           = [_outputs]\n\n_output_serializers = [\n    _serialize_json,\n\n]\n\nimport
           os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "name": "Produce list of dicts", "outputs": [{"name":
+          "image": "python:3.9"}}, "name": "Produce list of dicts", "outputs": [{"name":
           "Output", "type": "JsonArray"}]}', pipelines.kubeflow.org/component_ref: '{}'}
   - name: produce-list-of-ints
     container:
@@ -600,7 +600,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
     outputs:
       parameters:
       - name: produce-list-of-ints-Output
@@ -628,7 +628,7 @@ spec:
           = [_outputs]\n\n_output_serializers = [\n    _serialize_json,\n\n]\n\nimport
           os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "name": "Produce list of ints", "outputs": [{"name":
+          "image": "python:3.9"}}, "name": "Produce list of ints", "outputs": [{"name":
           "Output", "type": "JsonArray"}]}', pipelines.kubeflow.org/component_ref: '{}'}
   - name: produce-list-of-strings
     container:
@@ -682,7 +682,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
     outputs:
       parameters:
       - name: produce-list-of-strings-Output
@@ -710,7 +710,7 @@ spec:
           = [_outputs]\n\n_output_serializers = [\n    _serialize_json,\n\n]\n\nimport
           os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "name": "Produce list of strings", "outputs": [{"name":
+          "image": "python:3.9"}}, "name": "Produce list of strings", "outputs": [{"name":
           "Output", "type": "JsonArray"}]}', pipelines.kubeflow.org/component_ref: '{}'}
   - name: produce-str
     container:
@@ -755,7 +755,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
     outputs:
       parameters:
       - name: produce-str-Output
@@ -781,7 +781,7 @@ spec:
           = [_outputs]\n\n_output_serializers = [\n    _serialize_str,\n\n]\n\nimport
           os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "name": "Produce str", "outputs": [{"name": "Output",
+          "image": "python:3.9"}}, "name": "Produce str", "outputs": [{"name": "Output",
           "type": "String"}]}', pipelines.kubeflow.org/component_ref: '{}'}
   arguments:
     parameters: []
diff --git a/sdk/python/tests/compiler/testdata/parallelfor_pipeline_param_in_items_resolving.yaml b/sdk/python/tests/compiler/testdata/parallelfor_pipeline_param_in_items_resolving.yaml
index 64dcdbbcfe85..a4266ce56ccb 100644
--- a/sdk/python/tests/compiler/testdata/parallelfor_pipeline_param_in_items_resolving.yaml
+++ b/sdk/python/tests/compiler/testdata/parallelfor_pipeline_param_in_items_resolving.yaml
@@ -30,7 +30,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: loop-item-param-1}
@@ -46,7 +46,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.loop-item-param-1}}"}'}
   - name: consume-2
@@ -69,7 +69,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: loop-item-param-3-subvar-first_name}
@@ -85,7 +85,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.loop-item-param-3-subvar-first_name}}"}'}
   - name: consume-3
@@ -108,7 +108,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: loop-item-param-3-subvar-message}
@@ -124,7 +124,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.loop-item-param-3-subvar-message}}"}'}
   - name: consume-4
@@ -147,7 +147,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: loop-item-param-5-subvar-first_name}
@@ -163,7 +163,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.loop-item-param-5-subvar-first_name}}"}'}
   - name: consume-5
@@ -186,7 +186,7 @@ spec:
         _parsed_args = vars(_parser.parse_args())
 
         _outputs = consume(**_parsed_args)
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: loop-item-param-5-subvar-message}
@@ -202,7 +202,7 @@ spec:
           argparse\n_parser = argparse.ArgumentParser(prog=''Consume'', description='''')\n_parser.add_argument(\"--param1\",
           dest=\"param1\", type=str, required=True, default=argparse.SUPPRESS)\n_parsed_args
           = vars(_parser.parse_args())\n\n_outputs = consume(**_parsed_args)\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
+          "image": "python:3.9"}}, "inputs": [{"name": "param1"}], "name": "Consume"}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"param1":
           "{{inputs.parameters.loop-item-param-5-subvar-message}}"}'}
   - name: for-loop-2
@@ -336,7 +336,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: fname1}
@@ -366,7 +366,7 @@ spec:
           = [_outputs]\n\n_output_serializers = [\n    _serialize_str,\n\n]\n\nimport
           os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "fname1", "type": "String"}],
+          "image": "python:3.9"}}, "inputs": [{"name": "fname1", "type": "String"}],
           "name": "Produce message", "outputs": [{"name": "Output", "type": "String"}]}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"fname1":
           "{{inputs.parameters.fname1}}"}'}
@@ -414,7 +414,7 @@ spec:
                 pass
             with open(output_file, 'w') as f:
                 f.write(_output_serializers[idx](_outputs[idx]))
-      image: python:3.7
+      image: python:3.9
     inputs:
       parameters:
       - {name: fname2}
@@ -444,7 +444,7 @@ spec:
           = [_outputs]\n\n_output_serializers = [\n    _serialize_str,\n\n]\n\nimport
           os\nfor idx, output_file in enumerate(_output_files):\n    try:\n        os.makedirs(os.path.dirname(output_file))\n    except
           OSError:\n        pass\n    with open(output_file, ''w'') as f:\n        f.write(_output_serializers[idx](_outputs[idx]))\n"],
-          "image": "python:3.7"}}, "inputs": [{"name": "fname1", "type": "String"}],
+          "image": "python:3.9"}}, "inputs": [{"name": "fname1", "type": "String"}],
           "name": "Produce message", "outputs": [{"name": "Output", "type": "String"}]}',
         pipelines.kubeflow.org/component_ref: '{}', pipelines.kubeflow.org/arguments.parameters: '{"fname1":
           "{{inputs.parameters.fname2}}"}'}
diff --git a/sdk/python/tests/compiler/testdata/preemptible_tpu_gpu.yaml b/sdk/python/tests/compiler/testdata/preemptible_tpu_gpu.yaml
index 85fb22644c25..2710fc7c8d5c 100644
--- a/sdk/python/tests/compiler/testdata/preemptible_tpu_gpu.yaml
+++ b/sdk/python/tests/compiler/testdata/preemptible_tpu_gpu.yaml
@@ -27,7 +27,7 @@ spec:
         command:
           - sh
           - -c
-        image: python:alpine3.6
+        image: python:alpine3.9
         resources:
           limits:
             nvidia.com/gpu: 1
diff --git a/sdk/python/tests/compiler/testdata/recursive_do_while.py b/sdk/python/tests/compiler/testdata/recursive_do_while.py
index a7c8e0732397..188595f276b7 100644
--- a/sdk/python/tests/compiler/testdata/recursive_do_while.py
+++ b/sdk/python/tests/compiler/testdata/recursive_do_while.py
@@ -22,7 +22,7 @@ class FlipCoinOp(dsl.ContainerOp):
     def __init__(self):
         super(FlipCoinOp, self).__init__(
             name='Flip',
-            image='python:alpine3.6',
+            image='python:alpine3.9',
             command=['sh', '-c'],
             arguments=[
                 'python -c "import random; result = \'heads\' if random.randint(0,1) == 0 '
@@ -37,7 +37,7 @@ class PrintOp(dsl.ContainerOp):
     def __init__(self, msg):
         super(PrintOp, self).__init__(
             name='Print',
-            image='alpine:3.6',
+            image='alpine:3.9',
             command=['echo', msg],
         )
 
diff --git a/sdk/python/tests/compiler/testdata/recursive_do_while.yaml b/sdk/python/tests/compiler/testdata/recursive_do_while.yaml
index 3ed3bbf88f3a..2f7ce454fe3b 100644
--- a/sdk/python/tests/compiler/testdata/recursive_do_while.yaml
+++ b/sdk/python/tests/compiler/testdata/recursive_do_while.yaml
@@ -30,7 +30,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip
     outputs:
       artifacts:
@@ -47,7 +47,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip-2
     outputs:
       artifacts:
@@ -60,7 +60,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip-3
     outputs:
       artifacts:
@@ -124,7 +124,7 @@ spec:
       command:
       - echo
       - '{{inputs.parameters.flip-output}}'
-      image: alpine:3.6
+      image: alpine:3.9
     inputs:
       parameters:
       - name: flip-output
@@ -133,7 +133,7 @@ spec:
       command:
       - echo
       - cool, it is over. {{inputs.parameters.flip-output}}
-      image: alpine:3.6
+      image: alpine:3.9
     inputs:
       parameters:
       - name: flip-output
diff --git a/sdk/python/tests/compiler/testdata/recursive_while.py b/sdk/python/tests/compiler/testdata/recursive_while.py
index a4f7df99d843..4b7b442bd01c 100644
--- a/sdk/python/tests/compiler/testdata/recursive_while.py
+++ b/sdk/python/tests/compiler/testdata/recursive_while.py
@@ -21,7 +21,7 @@ class FlipCoinOp(dsl.ContainerOp):
     def __init__(self):
         super(FlipCoinOp, self).__init__(
             name='Flip',
-            image='python:alpine3.6',
+            image='python:alpine3.9',
             command=['sh', '-c'],
             arguments=[
                 'python -c "import random; result = \'heads\' if random.randint(0,1) == 0 '
@@ -36,7 +36,7 @@ class PrintOp(dsl.ContainerOp):
     def __init__(self, msg):
         super(PrintOp, self).__init__(
             name='Print',
-            image='alpine:3.6',
+            image='alpine:3.9',
             command=['echo', msg],
         )
 
diff --git a/sdk/python/tests/compiler/testdata/recursive_while.yaml b/sdk/python/tests/compiler/testdata/recursive_while.yaml
index eeed7c8ee744..b6448522cd76 100644
--- a/sdk/python/tests/compiler/testdata/recursive_while.yaml
+++ b/sdk/python/tests/compiler/testdata/recursive_while.yaml
@@ -44,7 +44,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip
     outputs:
       artifacts:
@@ -61,7 +61,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip-2
     outputs:
       artifacts:
@@ -74,7 +74,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: flip-3
     outputs:
       artifacts:
@@ -126,7 +126,7 @@ spec:
       command:
       - echo
       - '{{inputs.parameters.flip-output}}'
-      image: alpine:3.6
+      image: alpine:3.9
     inputs:
       parameters:
       - name: flip-output
@@ -135,7 +135,7 @@ spec:
       command:
       - echo
       - cool, it is over. {{inputs.parameters.flip-output}}
-      image: alpine:3.6
+      image: alpine:3.9
     inputs:
       parameters:
       - name: flip-output
diff --git a/sdk/python/tests/compiler/testdata/timeout.py b/sdk/python/tests/compiler/testdata/timeout.py
index 3db8e3743ca4..574f24b3eb06 100755
--- a/sdk/python/tests/compiler/testdata/timeout.py
+++ b/sdk/python/tests/compiler/testdata/timeout.py
@@ -22,7 +22,7 @@ class RandomFailure1Op(dsl.ContainerOp):
     def __init__(self, exit_codes):
         super(RandomFailure1Op, self).__init__(
             name='random_failure',
-            image='python:alpine3.6',
+            image='python:alpine3.9',
             command=['python', '-c'],
             arguments=[
                 "import random; import sys; exit_code = random.choice([%s]); print(exit_code); sys.exit(exit_code)"
diff --git a/sdk/python/tests/compiler/testdata/timeout.yaml b/sdk/python/tests/compiler/testdata/timeout.yaml
index 95895f1671da..8bf286a8104d 100644
--- a/sdk/python/tests/compiler/testdata/timeout.yaml
+++ b/sdk/python/tests/compiler/testdata/timeout.yaml
@@ -28,7 +28,7 @@ spec:
       command:
       - python
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: random-failure
   - container:
       args:
@@ -37,5 +37,5 @@ spec:
       command:
       - python
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: random-failure-2
diff --git a/sdk/python/tests/compiler/testdata/uri_artifacts.py b/sdk/python/tests/compiler/testdata/uri_artifacts.py
index f969c59385b1..43c529bbca43 100644
--- a/sdk/python/tests/compiler/testdata/uri_artifacts.py
+++ b/sdk/python/tests/compiler/testdata/uri_artifacts.py
@@ -73,7 +73,7 @@ def get_code(self,):
 - {name: output, type: String}
 implementation:
   container:
-    image: python:alpine3.6
+    image: python:alpine3.9
     command:
     - sh
     - -c
diff --git a/sdk/python/tests/compiler/testdata/uri_artifacts.yaml b/sdk/python/tests/compiler/testdata/uri_artifacts.yaml
index 229978c88246..60192fcc6ff0 100644
--- a/sdk/python/tests/compiler/testdata/uri_artifacts.yaml
+++ b/sdk/python/tests/compiler/testdata/uri_artifacts.yaml
@@ -70,7 +70,7 @@ spec:
           "outputArtifacts": {}}'}
       envFrom:
       - configMapRef: {name: metadata-grpc-configmap, optional: true}
-      image: python:alpine3.6
+      image: python:alpine3.9
       volumeMounts:
       - {mountPath: /kfp-launcher, name: kfp-launcher}
     inputs:
diff --git a/sdk/python/tests/compiler/testdata/withparam_global.py b/sdk/python/tests/compiler/testdata/withparam_global.py
index 4aaa989a6ac7..fd8575d10528 100644
--- a/sdk/python/tests/compiler/testdata/withparam_global.py
+++ b/sdk/python/tests/compiler/testdata/withparam_global.py
@@ -19,7 +19,7 @@
 def pipeline(loopidy_doop: list = [3, 5, 7, 9]):
     op0 = dsl.ContainerOp(
         name="my-out-cop0",
-        image='python:alpine3.6',
+        image='python:alpine3.9',
         command=["sh", "-c"],
         arguments=[
             'python -c "import json; import sys; json.dump([i for i in range(20, 31)], open(\'/tmp/out.json\', \'w\'))"'
diff --git a/sdk/python/tests/compiler/testdata/withparam_global.yaml b/sdk/python/tests/compiler/testdata/withparam_global.yaml
index b55f62bd2c7c..303c9a1d7648 100644
--- a/sdk/python/tests/compiler/testdata/withparam_global.yaml
+++ b/sdk/python/tests/compiler/testdata/withparam_global.yaml
@@ -43,7 +43,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: my-out-cop0
     outputs:
       artifacts:
diff --git a/sdk/python/tests/compiler/testdata/withparam_global_dict.py b/sdk/python/tests/compiler/testdata/withparam_global_dict.py
index 5c896614e828..d7501f0dc8a5 100644
--- a/sdk/python/tests/compiler/testdata/withparam_global_dict.py
+++ b/sdk/python/tests/compiler/testdata/withparam_global_dict.py
@@ -19,7 +19,7 @@
 def pipeline(loopidy_doop: dict = [{'a': 1, 'b': 2}, {'a': 10, 'b': 20}]):
     op0 = dsl.ContainerOp(
         name="my-out-cop0",
-        image='python:alpine3.6',
+        image='python:alpine3.9',
         command=["sh", "-c"],
         arguments=[
             'python -c "import json; import sys; json.dump([i for i in range(20, 31)], open(\'/tmp/out.json\', \'w\'))"'
diff --git a/sdk/python/tests/compiler/testdata/withparam_global_dict.yaml b/sdk/python/tests/compiler/testdata/withparam_global_dict.yaml
index ced4c60bfabe..3880e7dfd2b8 100644
--- a/sdk/python/tests/compiler/testdata/withparam_global_dict.yaml
+++ b/sdk/python/tests/compiler/testdata/withparam_global_dict.yaml
@@ -43,7 +43,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: my-out-cop0
     outputs:
       artifacts:
diff --git a/sdk/python/tests/compiler/testdata/withparam_output.py b/sdk/python/tests/compiler/testdata/withparam_output.py
index bbbfa8fed766..845e46afe645 100644
--- a/sdk/python/tests/compiler/testdata/withparam_output.py
+++ b/sdk/python/tests/compiler/testdata/withparam_output.py
@@ -19,7 +19,7 @@
 def pipeline():
     op0 = dsl.ContainerOp(
         name="my-out-cop0",
-        image='python:alpine3.6',
+        image='python:alpine3.9',
         command=["sh", "-c"],
         arguments=[
             'python -c "import json; import sys; json.dump([i for i in range(20, 31)], open(\'/tmp/out.json\', \'w\'))"'
diff --git a/sdk/python/tests/compiler/testdata/withparam_output.yaml b/sdk/python/tests/compiler/testdata/withparam_output.yaml
index 9019ab33686e..4a59c3cb9b1d 100644
--- a/sdk/python/tests/compiler/testdata/withparam_output.yaml
+++ b/sdk/python/tests/compiler/testdata/withparam_output.yaml
@@ -40,7 +40,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: my-out-cop0
     outputs:
       artifacts:
diff --git a/sdk/python/tests/compiler/testdata/withparam_output_dict.py b/sdk/python/tests/compiler/testdata/withparam_output_dict.py
index 8b5470a37c9b..e4e46fd8fc6b 100644
--- a/sdk/python/tests/compiler/testdata/withparam_output_dict.py
+++ b/sdk/python/tests/compiler/testdata/withparam_output_dict.py
@@ -19,7 +19,7 @@
 def pipeline():
     op0 = dsl.ContainerOp(
         name="my-out-cop0",
-        image='python:alpine3.6',
+        image='python:alpine3.9',
         command=["sh", "-c"],
         arguments=[
             'python -c "import json; import sys; json.dump([{\'a\': 1, \'b\': 2}, {\'a\': 10, \'b\': 20}], open(\'/tmp/out.json\', \'w\'))"'
diff --git a/sdk/python/tests/compiler/testdata/withparam_output_dict.yaml b/sdk/python/tests/compiler/testdata/withparam_output_dict.yaml
index bd484ef393fb..a396d442ad29 100644
--- a/sdk/python/tests/compiler/testdata/withparam_output_dict.yaml
+++ b/sdk/python/tests/compiler/testdata/withparam_output_dict.yaml
@@ -40,7 +40,7 @@ spec:
       command:
       - sh
       - -c
-      image: python:alpine3.6
+      image: python:alpine3.9
     name: my-out-cop0
     outputs:
       artifacts:
diff --git a/sdk/python/tests/local_runner_test.py b/sdk/python/tests/local_runner_test.py
index 7074f32365a6..9522004ed519 100644
--- a/sdk/python/tests/local_runner_test.py
+++ b/sdk/python/tests/local_runner_test.py
@@ -22,7 +22,7 @@
 InputPath = kfp.components.InputPath()
 OutputPath = kfp.components.OutputPath()
 
-BASE_IMAGE = "python:3.7"
+BASE_IMAGE = "python:3.9"
 
 
 def light_component(base_image: str = BASE_IMAGE,):
@@ -30,7 +30,7 @@ def light_component(base_image: str = BASE_IMAGE,):
 
     Usage:
     ```python
-    @light_component(base_image="python:3.7")
+    @light_component(base_image="python:3.9")
     def a_component(src: kfp.components.InputPath(), ...):
         ...
     ```
diff --git a/sdk/runtime_tests/test_data/pipeline_with_task_final_status.yaml b/sdk/runtime_tests/test_data/pipeline_with_task_final_status.yaml
index 18ae5fa44dc4..a2d613086648 100644
--- a/sdk/runtime_tests/test_data/pipeline_with_task_final_status.yaml
+++ b/sdk/runtime_tests/test_data/pipeline_with_task_final_status.yaml
@@ -88,7 +88,7 @@ deploymentSpec:
           \    print('Pipeline task name: ', status.pipeline_task_name)\n    print('Error\
           \ code: ', status.error_code)\n    print('Error message: ', status.error_message)\n\
           \n"
-        image: python:3.7
+        image: python:3.9
     exec-fail-op:
       container:
         args:
@@ -117,7 +117,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef fail_op(message: str):\n    \"\"\"Fails.\"\"\"\n    import sys\n\
           \    print(message)\n    sys.exit(1)\n\n"
-        image: python:3.7
+        image: python:3.9
     exec-print-op:
       container:
         args:
@@ -146,7 +146,7 @@ deploymentSpec:
         - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\
           \ *\n\ndef print_op(message: str):\n    \"\"\"Prints a message.\"\"\"\n\
           \    print(message)\n\n"
-        image: python:3.7
+        image: python:3.9
 pipelineInfo:
   name: pipeline-with-task-final-status
 root:
diff --git a/test/frontend-integration-test/tensorboard-example.yaml b/test/frontend-integration-test/tensorboard-example.yaml
index 14bb4a5fbf59..6852fc3717e6 100644
--- a/test/frontend-integration-test/tensorboard-example.yaml
+++ b/test/frontend-integration-test/tensorboard-example.yaml
@@ -22,7 +22,7 @@ spec:
   templates:
   - name: tensorboard-example
     script:
-      image: python:alpine3.6
+      image: python:alpine3.9
       command: [python]
       source: |
         import json
diff --git a/test/kfp-kubernetes-execution-tests/requirements.txt b/test/kfp-kubernetes-execution-tests/requirements.txt
index bf44f1204984..2552b2cbb65e 100644
--- a/test/kfp-kubernetes-execution-tests/requirements.txt
+++ b/test/kfp-kubernetes-execution-tests/requirements.txt
@@ -1,3 +1,3 @@
 sdk/python
-pytest==7.1.3
-pytest-asyncio-cooperative==0.28.0
+pytest==8.3.2
+pytest-asyncio-cooperative==0.37.0
diff --git a/test/sdk-execution-tests/requirements.txt b/test/sdk-execution-tests/requirements.txt
index bf44f1204984..2552b2cbb65e 100644
--- a/test/sdk-execution-tests/requirements.txt
+++ b/test/sdk-execution-tests/requirements.txt
@@ -1,3 +1,3 @@
 sdk/python
-pytest==7.1.3
-pytest-asyncio-cooperative==0.28.0
+pytest==8.3.2
+pytest-asyncio-cooperative==0.37.0