We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
kfp component ml_engine deploy version param is incorrectly typed
### What steps did you take:

I tried to specify the `version` param to the gcp ml_engine deploy component via:

```
 mlengine_deploy_op = comp.load_component_from_url('https://raw.githubusercontent.com/kubeflow/pipelines/1.0.0/components/gcp/ml_engine/deploy/component.yaml')

. . .

 upload_task = mlengine_deploy_op(
    model_id=model_id,
    project_id=project_id,
    python_version=python_version,
    runtime_version=runtime_version,
    version_id=version_id,
    model_uri=model_uri,
    model={
        'onlinePredictionLogging': True,
        'onlinePredictionConsoleLogging': True,
    },
    version={
        'packageUris': package_uris,
        'predictionClass': prediction_class,
    },
)
```

### What happened:

Received a type error that str object (version) does not support assignment
```
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/local/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/ml/kfp_component/launcher/__main__.py", line 34, in <module>
    main()
  File "/ml/kfp_component/launcher/__main__.py", line 31, in main
    launch(args.file_or_module, args.args)
  File "kfp_component/launcher/launcher.py", line 45, in launch
    return fire.Fire(module, command=args, name=module.__name__)
  File "/usr/local/lib/python2.7/site-packages/fire/core.py", line 127, in Fire
    component_trace = _Fire(component, args, context, name)
  File "/usr/local/lib/python2.7/site-packages/fire/core.py", line 366, in _Fire
    component, remaining_args)
  File "/usr/local/lib/python2.7/site-packages/fire/core.py", line 542, in _CallCallable
    result = fn(*varargs, **kwargs)
  File "kfp_component/google/ml_engine/_deploy.py", line 68, in deploy
    wait_interval)
  File "kfp_component/google/ml_engine/_create_version.py", line 55, in create_version
    version['deploymentUri'] = deployemnt_uri
TypeError: 'str' object does not support item assignment
```

### What did you expect to happen:

I expected to be able to pass additional version parameters as a dictionary as described in https://cloud.google.com/ml-engine/reference/rest/v1/projects.models.versions and https://github.com/kubeflow/pipelines/blob/master/components/gcp/ml_engine/deploy/component.yaml#L64:L69

However, this type is being declared as a str when it should be a dict: https://github.com/kubeflow/pipelines/blob/master/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py#L47

This is ultimately based on the assumption that fire is using the docstring to do type hinting.

### Environment:
How did you deploy Kubeflow Pipelines (KFP)?
Deployed via AI-Platform Pipelines

KFP version:
```
Build commit: 9c16e12
``` 

KFP SDK version: 
```
kfp                      0.5.1
kfp-server-api           0.5.0
```

/kind bug
/area sdk
flexible pipeline service (host) path in client SDK 
when creating an SDK `Client()` the path to `ml-pipeline` API service is loaded from a hard coded value (`ml-pipeline.kubeflow.svc.cluster.local:8888`) which indicate a specific k8s namespace. it can be valuable to load that default value from an env variable, i.e. changing the line in `_client.py` from:

`config.host = host if host else Client.IN_CLUSTER_DNS_NAME`

to:

`config.host = host or os.environ.get('ML_PIPELINE_DNS_NAME',Client.IN_CLUSTER_DNS_NAME)`

also note that when a user provide the `host` parameter, the ipython output points to the API server and not to the UI service (see the logic in `_get_url_prefix()`), it seems like a potential bug

if its acceptable i can submit a PR for the line change above
 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py`
Content:
```
1 # Copyright 2018 Google LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import json
16 import logging
17 import time
18 import re
19 
20 from googleapiclient import errors
21 from fire import decorators
22 
23 from kfp_component.core import KfpExecutionContext, display
24 from ._client import MLEngineClient
25 from .. import common as gcp_common
26 from ._common_ops import wait_existing_version, wait_for_operation_done
27 
28 @decorators.SetParseFns(python_version=str, runtime_version=str)
29 def create_version(model_name, deployemnt_uri=None, version_id=None, 
30     runtime_version=None, python_version=None, version=None, 
31     replace_existing=False, wait_interval=30):
32     """Creates a MLEngine version and wait for the operation to be done.
33 
34     Args:
35         model_name (str): required, the name of the parent model.
36         deployment_uri (str): optional, the Google Cloud Storage location of 
37             the trained model used to create the version.
38         version_id (str): optional, the user provided short name of 
39             the version. If it is not provided, the operation uses a random name.
40         runtime_version (str): optinal, the Cloud ML Engine runtime version 
41             to use for this deployment. If not set, Cloud ML Engine uses 
42             the default stable version, 1.0. 
43         python_version (str): optinal, the version of Python used in prediction. 
44             If not set, the default version is '2.7'. Python '3.5' is available
45             when runtimeVersion is set to '1.4' and above. Python '2.7' works 
46             with all supported runtime versions.
47         version (str): optional, the payload of the new version.
48         replace_existing (boolean): boolean flag indicates whether to replace 
49             existing version in case of conflict.
50         wait_interval (int): the interval to wait for a long running operation.
51     """
52     if not version:
53         version = {}
54     if deployemnt_uri:
55         version['deploymentUri'] = deployemnt_uri
56     if version_id:
57         version['name'] = version_id
58     if runtime_version:
59         version['runtimeVersion'] = runtime_version
60     if python_version:
61         version['pythonVersion'] = python_version
62 
63     return CreateVersionOp(model_name, version, 
64         replace_existing, wait_interval).execute_and_wait()
65 
66 class CreateVersionOp:
67     def __init__(self, model_name, version, 
68         replace_existing, wait_interval):
69         self._ml = MLEngineClient()
70         self._model_name = model_name
71         self._project_id, self._model_id = self._parse_model_name(model_name)
72         # The name of the version resource, which is in the format 
73         # of projects/*/models/*/versions/*
74         self._version_name = None
75         # The user provide short name of the version.
76         self._version_id = None
77         # The full payload of the version resource.
78         self._version = version
79         self._replace_existing = replace_existing
80         self._wait_interval = wait_interval
81         self._create_operation_name = None
82         self._delete_operation_name = None
83 
84     def execute_and_wait(self):
85         with KfpExecutionContext(on_cancel=self._cancel) as ctx:
86             self._set_version_name(ctx.context_id())
87             self._dump_metadata()
88             existing_version = wait_existing_version(self._ml, 
89                 self._version_name, 
90                 self._wait_interval)
91             if existing_version and self._is_dup_version(existing_version):
92                 return self._handle_completed_version(existing_version)
93 
94             if existing_version and self._replace_existing:
95                 logging.info('Deleting existing version...')
96                 self._delete_version_and_wait()
97             elif existing_version:
98                 raise RuntimeError(
99                     'Existing version conflicts with the name of the new version.')
100             
101             created_version = self._create_version_and_wait()
102             return self._handle_completed_version(created_version)
103     
104     def _parse_model_name(self, model_name):
105         match = re.search(r'^projects/([^/]+)/models/([^/]+)$', model_name)
106         if not match:
107             raise ValueError('model name "{}" is not in desired format.'.format(model_name))
108         return (match.group(1), match.group(2))
109 
110     def _set_version_name(self, context_id):
111         name = self._version.get('name', None)
112         if not name:
113             name = 'ver_' + context_id
114         name = gcp_common.normalize_name(name)
115         self._version_id = name
116         self._version['name'] = name
117         self._version_name = '{}/versions/{}'.format(self._model_name, name)
118 
119     def _cancel(self):
120         if self._delete_operation_name:
121             self._ml.cancel_operation(self._delete_operation_name)
122 
123         if self._create_operation_name:
124             self._ml.cancel_operation(self._create_operation_name)
125 
126     def _create_version_and_wait(self):
127         operation = self._ml.create_version(self._model_name, self._version)
128         # Cache operation name for cancellation.
129         self._create_operation_name = operation.get('name')
130         try:
131             operation = wait_for_operation_done(
132                 self._ml,
133                 self._create_operation_name, 
134                 'create version',
135                 self._wait_interval)
136         finally:
137             self._create_operation_name = None
138         return operation.get('response', None)
139 
140     def _delete_version_and_wait(self):
141         operation = self._ml.delete_version(self._version_name)
142         # Cache operation name for cancellation.
143         self._delete_operation_name = operation.get('name')
144         try:
145             wait_for_operation_done(
146                 self._ml,
147                 self._delete_operation_name, 
148                 'delete version',
149                 self._wait_interval)
150         finally:
151             self._delete_operation_name = None
152         
153     def _handle_completed_version(self, version):
154         state = version.get('state', None)
155         if state == 'FAILED':
156             error_message = version.get('errorMessage', 'Unknown failure')
157             raise RuntimeError('Version is in failed state: {}'.format(
158                 error_message))
159         # Workaround issue that CMLE doesn't return the full version name.
160         version['name'] = self._version_name
161         self._dump_version(version)
162         return version
163 
164     def _dump_metadata(self):
165         display.display(display.Link(
166             'https://console.cloud.google.com/mlengine/models/{}/versions/{}?project={}'.format(
167                 self._model_id, self._version_id, self._project_id),
168             'Version Details'
169         ))
170         display.display(display.Markdown('''
171 ## Online Prediction
172 
173 ### REST endpoint
174 The REST endpoint for online prediction is as follows:
175 ```
176 POST https://ml.googleapis.com/v1/{}:predict
177 ```
178 Try the REST endpoint in [Google OAuth 2.0 Playgound](https://developers.google.com/oauthplayground/#step3\
179 &apisSelect=https://www.googleapis.com/auth/cloud-platform&postData={{"instances":[]}}\
180 &url=https://ml.googleapis.com/v1/{}:predict&content_type=application/json&http_method=POST).
181 
182 ### GCloud command
183 ```bash
184 gcloud ai-platform predict --model {}  \
185                    --version {} \
186                    --json-instances instances.json
187 ```
188         '''.format(self._version_name, self._version_name, self._model_id, self._version_id)))
189 
190     def _dump_version(self, version):
191         logging.info('Dumping version: {}'.format(version))
192         gcp_common.dump_file('/tmp/kfp/output/ml_engine/version.json', json.dumps(version))
193         gcp_common.dump_file('/tmp/kfp/output/ml_engine/version_name.txt', version['name'])
194 
195     def _is_dup_version(self, existing_version):
196         return not gcp_common.check_resource_changed(
197             self._version,
198             existing_version,
199             ['description', 'deploymentUri', 
200                 'runtimeVersion', 'machineType', 'labels',
201                 'framework', 'pythonVersion', 'autoScaling',
202                 'manualScaling'])
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py b/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py
--- a/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py
+++ b/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py
@@ -44,7 +44,7 @@
             If not set, the default version is '2.7'. Python '3.5' is available
             when runtimeVersion is set to '1.4' and above. Python '2.7' works 
             with all supported runtime versions.
-        version (str): optional, the payload of the new version.
+        version (dict): optional, the payload of the new version.
         replace_existing (boolean): boolean flag indicates whether to replace 
             existing version in case of conflict.
         wait_interval (int): the interval to wait for a long running operation.
@@ -199,4 +199,4 @@
             ['description', 'deploymentUri', 
                 'runtimeVersion', 'machineType', 'labels',
                 'framework', 'pythonVersion', 'autoScaling',
-                'manualScaling'])
\ No newline at end of file
+                'manualScaling'])

{"golden_diff": "diff --git a/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py b/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py\n--- a/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py\n+++ b/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py\n@@ -44,7 +44,7 @@\n             If not set, the default version is '2.7'. Python '3.5' is available\n             when runtimeVersion is set to '1.4' and above. Python '2.7' works \n             with all supported runtime versions.\n-        version (str): optional, the payload of the new version.\n+        version (dict): optional, the payload of the new version.\n         replace_existing (boolean): boolean flag indicates whether to replace \n             existing version in case of conflict.\n         wait_interval (int): the interval to wait for a long running operation.\n@@ -199,4 +199,4 @@\n             ['description', 'deploymentUri', \n                 'runtimeVersion', 'machineType', 'labels',\n                 'framework', 'pythonVersion', 'autoScaling',\n-                'manualScaling'])\n\\ No newline at end of file\n+                'manualScaling'])\n", "issue": "kfp component ml_engine deploy version param is incorrectly typed\n### What steps did you take:\r\n\r\nI tried to specify the `version` param to the gcp ml_engine deploy component via:\r\n\r\n```\r\n mlengine_deploy_op = comp.load_component_from_url('https://raw.githubusercontent.com/kubeflow/pipelines/1.0.0/components/gcp/ml_engine/deploy/component.yaml')\r\n\r\n. . .\r\n\r\n upload_task = mlengine_deploy_op(\r\n    model_id=model_id,\r\n    project_id=project_id,\r\n    python_version=python_version,\r\n    runtime_version=runtime_version,\r\n    version_id=version_id,\r\n    model_uri=model_uri,\r\n    model={\r\n        'onlinePredictionLogging': True,\r\n        'onlinePredictionConsoleLogging': True,\r\n    },\r\n    version={\r\n        'packageUris': package_uris,\r\n        'predictionClass': prediction_class,\r\n    },\r\n)\r\n```\r\n\r\n### What happened:\r\n\r\nReceived a type error that str object (version) does not support assignment\r\n```\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python2.7/runpy.py\", line 174, in _run_module_as_main\r\n    \"__main__\", fname, loader, pkg_name)\r\n  File \"/usr/local/lib/python2.7/runpy.py\", line 72, in _run_code\r\n    exec code in run_globals\r\n  File \"/ml/kfp_component/launcher/__main__.py\", line 34, in <module>\r\n    main()\r\n  File \"/ml/kfp_component/launcher/__main__.py\", line 31, in main\r\n    launch(args.file_or_module, args.args)\r\n  File \"kfp_component/launcher/launcher.py\", line 45, in launch\r\n    return fire.Fire(module, command=args, name=module.__name__)\r\n  File \"/usr/local/lib/python2.7/site-packages/fire/core.py\", line 127, in Fire\r\n    component_trace = _Fire(component, args, context, name)\r\n  File \"/usr/local/lib/python2.7/site-packages/fire/core.py\", line 366, in _Fire\r\n    component, remaining_args)\r\n  File \"/usr/local/lib/python2.7/site-packages/fire/core.py\", line 542, in _CallCallable\r\n    result = fn(*varargs, **kwargs)\r\n  File \"kfp_component/google/ml_engine/_deploy.py\", line 68, in deploy\r\n    wait_interval)\r\n  File \"kfp_component/google/ml_engine/_create_version.py\", line 55, in create_version\r\n    version['deploymentUri'] = deployemnt_uri\r\nTypeError: 'str' object does not support item assignment\r\n```\r\n\r\n### What did you expect to happen:\r\n\r\nI expected to be able to pass additional version parameters as a dictionary as described in https://cloud.google.com/ml-engine/reference/rest/v1/projects.models.versions and https://github.com/kubeflow/pipelines/blob/master/components/gcp/ml_engine/deploy/component.yaml#L64:L69\r\n\r\nHowever, this type is being declared as a str when it should be a dict: https://github.com/kubeflow/pipelines/blob/master/components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py#L47\r\n\r\nThis is ultimately based on the assumption that fire is using the docstring to do type hinting.\r\n\r\n### Environment:\r\nHow did you deploy Kubeflow Pipelines (KFP)?\r\nDeployed via AI-Platform Pipelines\r\n\r\nKFP version:\r\n```\r\nBuild commit: 9c16e12\r\n``` \r\n\r\nKFP SDK version: \r\n```\r\nkfp                      0.5.1\r\nkfp-server-api           0.5.0\r\n```\r\n\r\n/kind bug\r\n/area sdk\nflexible pipeline service (host) path in client SDK \nwhen creating an SDK `Client()` the path to `ml-pipeline` API service is loaded from a hard coded value (`ml-pipeline.kubeflow.svc.cluster.local:8888`) which indicate a specific k8s namespace. it can be valuable to load that default value from an env variable, i.e. changing the line in `_client.py` from:\r\n\r\n`config.host = host if host else Client.IN_CLUSTER_DNS_NAME`\r\n\r\nto:\r\n\r\n`config.host = host or os.environ.get('ML_PIPELINE_DNS_NAME',Client.IN_CLUSTER_DNS_NAME)`\r\n\r\nalso note that when a user provide the `host` parameter, the ipython output points to the API server and not to the UI service (see the logic in `_get_url_prefix()`), it seems like a potential bug\r\n\r\nif its acceptable i can submit a PR for the line change above\r\n \n", "before_files": [{"content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\nimport logging\nimport time\nimport re\n\nfrom googleapiclient import errors\nfrom fire import decorators\n\nfrom kfp_component.core import KfpExecutionContext, display\nfrom ._client import MLEngineClient\nfrom .. import common as gcp_common\nfrom ._common_ops import wait_existing_version, wait_for_operation_done\n\n@decorators.SetParseFns(python_version=str, runtime_version=str)\ndef create_version(model_name, deployemnt_uri=None, version_id=None, \n    runtime_version=None, python_version=None, version=None, \n    replace_existing=False, wait_interval=30):\n    \"\"\"Creates a MLEngine version and wait for the operation to be done.\n\n    Args:\n        model_name (str): required, the name of the parent model.\n        deployment_uri (str): optional, the Google Cloud Storage location of \n            the trained model used to create the version.\n        version_id (str): optional, the user provided short name of \n            the version. If it is not provided, the operation uses a random name.\n        runtime_version (str): optinal, the Cloud ML Engine runtime version \n            to use for this deployment. If not set, Cloud ML Engine uses \n            the default stable version, 1.0. \n        python_version (str): optinal, the version of Python used in prediction. \n            If not set, the default version is '2.7'. Python '3.5' is available\n            when runtimeVersion is set to '1.4' and above. Python '2.7' works \n            with all supported runtime versions.\n        version (str): optional, the payload of the new version.\n        replace_existing (boolean): boolean flag indicates whether to replace \n            existing version in case of conflict.\n        wait_interval (int): the interval to wait for a long running operation.\n    \"\"\"\n    if not version:\n        version = {}\n    if deployemnt_uri:\n        version['deploymentUri'] = deployemnt_uri\n    if version_id:\n        version['name'] = version_id\n    if runtime_version:\n        version['runtimeVersion'] = runtime_version\n    if python_version:\n        version['pythonVersion'] = python_version\n\n    return CreateVersionOp(model_name, version, \n        replace_existing, wait_interval).execute_and_wait()\n\nclass CreateVersionOp:\n    def __init__(self, model_name, version, \n        replace_existing, wait_interval):\n        self._ml = MLEngineClient()\n        self._model_name = model_name\n        self._project_id, self._model_id = self._parse_model_name(model_name)\n        # The name of the version resource, which is in the format \n        # of projects/*/models/*/versions/*\n        self._version_name = None\n        # The user provide short name of the version.\n        self._version_id = None\n        # The full payload of the version resource.\n        self._version = version\n        self._replace_existing = replace_existing\n        self._wait_interval = wait_interval\n        self._create_operation_name = None\n        self._delete_operation_name = None\n\n    def execute_and_wait(self):\n        with KfpExecutionContext(on_cancel=self._cancel) as ctx:\n            self._set_version_name(ctx.context_id())\n            self._dump_metadata()\n            existing_version = wait_existing_version(self._ml, \n                self._version_name, \n                self._wait_interval)\n            if existing_version and self._is_dup_version(existing_version):\n                return self._handle_completed_version(existing_version)\n\n            if existing_version and self._replace_existing:\n                logging.info('Deleting existing version...')\n                self._delete_version_and_wait()\n            elif existing_version:\n                raise RuntimeError(\n                    'Existing version conflicts with the name of the new version.')\n            \n            created_version = self._create_version_and_wait()\n            return self._handle_completed_version(created_version)\n    \n    def _parse_model_name(self, model_name):\n        match = re.search(r'^projects/([^/]+)/models/([^/]+)$', model_name)\n        if not match:\n            raise ValueError('model name \"{}\" is not in desired format.'.format(model_name))\n        return (match.group(1), match.group(2))\n\n    def _set_version_name(self, context_id):\n        name = self._version.get('name', None)\n        if not name:\n            name = 'ver_' + context_id\n        name = gcp_common.normalize_name(name)\n        self._version_id = name\n        self._version['name'] = name\n        self._version_name = '{}/versions/{}'.format(self._model_name, name)\n\n    def _cancel(self):\n        if self._delete_operation_name:\n            self._ml.cancel_operation(self._delete_operation_name)\n\n        if self._create_operation_name:\n            self._ml.cancel_operation(self._create_operation_name)\n\n    def _create_version_and_wait(self):\n        operation = self._ml.create_version(self._model_name, self._version)\n        # Cache operation name for cancellation.\n        self._create_operation_name = operation.get('name')\n        try:\n            operation = wait_for_operation_done(\n                self._ml,\n                self._create_operation_name, \n                'create version',\n                self._wait_interval)\n        finally:\n            self._create_operation_name = None\n        return operation.get('response', None)\n\n    def _delete_version_and_wait(self):\n        operation = self._ml.delete_version(self._version_name)\n        # Cache operation name for cancellation.\n        self._delete_operation_name = operation.get('name')\n        try:\n            wait_for_operation_done(\n                self._ml,\n                self._delete_operation_name, \n                'delete version',\n                self._wait_interval)\n        finally:\n            self._delete_operation_name = None\n        \n    def _handle_completed_version(self, version):\n        state = version.get('state', None)\n        if state == 'FAILED':\n            error_message = version.get('errorMessage', 'Unknown failure')\n            raise RuntimeError('Version is in failed state: {}'.format(\n                error_message))\n        # Workaround issue that CMLE doesn't return the full version name.\n        version['name'] = self._version_name\n        self._dump_version(version)\n        return version\n\n    def _dump_metadata(self):\n        display.display(display.Link(\n            'https://console.cloud.google.com/mlengine/models/{}/versions/{}?project={}'.format(\n                self._model_id, self._version_id, self._project_id),\n            'Version Details'\n        ))\n        display.display(display.Markdown('''\n## Online Prediction\n\n### REST endpoint\nThe REST endpoint for online prediction is as follows:\n```\nPOST https://ml.googleapis.com/v1/{}:predict\n```\nTry the REST endpoint in [Google OAuth 2.0 Playgound](https://developers.google.com/oauthplayground/#step3\\\n&apisSelect=https://www.googleapis.com/auth/cloud-platform&postData={{\"instances\":[]}}\\\n&url=https://ml.googleapis.com/v1/{}:predict&content_type=application/json&http_method=POST).\n\n### GCloud command\n```bash\ngcloud ai-platform predict --model {}  \\\n                   --version {} \\\n                   --json-instances instances.json\n```\n        '''.format(self._version_name, self._version_name, self._model_id, self._version_id)))\n\n    def _dump_version(self, version):\n        logging.info('Dumping version: {}'.format(version))\n        gcp_common.dump_file('/tmp/kfp/output/ml_engine/version.json', json.dumps(version))\n        gcp_common.dump_file('/tmp/kfp/output/ml_engine/version_name.txt', version['name'])\n\n    def _is_dup_version(self, existing_version):\n        return not gcp_common.check_resource_changed(\n            self._version,\n            existing_version,\n            ['description', 'deploymentUri', \n                'runtimeVersion', 'machineType', 'labels',\n                'framework', 'pythonVersion', 'autoScaling',\n                'manualScaling'])", "path": "components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py"}], "after_files": [{"content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\nimport logging\nimport time\nimport re\n\nfrom googleapiclient import errors\nfrom fire import decorators\n\nfrom kfp_component.core import KfpExecutionContext, display\nfrom ._client import MLEngineClient\nfrom .. import common as gcp_common\nfrom ._common_ops import wait_existing_version, wait_for_operation_done\n\n@decorators.SetParseFns(python_version=str, runtime_version=str)\ndef create_version(model_name, deployemnt_uri=None, version_id=None, \n    runtime_version=None, python_version=None, version=None, \n    replace_existing=False, wait_interval=30):\n    \"\"\"Creates a MLEngine version and wait for the operation to be done.\n\n    Args:\n        model_name (str): required, the name of the parent model.\n        deployment_uri (str): optional, the Google Cloud Storage location of \n            the trained model used to create the version.\n        version_id (str): optional, the user provided short name of \n            the version. If it is not provided, the operation uses a random name.\n        runtime_version (str): optinal, the Cloud ML Engine runtime version \n            to use for this deployment. If not set, Cloud ML Engine uses \n            the default stable version, 1.0. \n        python_version (str): optinal, the version of Python used in prediction. \n            If not set, the default version is '2.7'. Python '3.5' is available\n            when runtimeVersion is set to '1.4' and above. Python '2.7' works \n            with all supported runtime versions.\n        version (dict): optional, the payload of the new version.\n        replace_existing (boolean): boolean flag indicates whether to replace \n            existing version in case of conflict.\n        wait_interval (int): the interval to wait for a long running operation.\n    \"\"\"\n    if not version:\n        version = {}\n    if deployemnt_uri:\n        version['deploymentUri'] = deployemnt_uri\n    if version_id:\n        version['name'] = version_id\n    if runtime_version:\n        version['runtimeVersion'] = runtime_version\n    if python_version:\n        version['pythonVersion'] = python_version\n\n    return CreateVersionOp(model_name, version, \n        replace_existing, wait_interval).execute_and_wait()\n\nclass CreateVersionOp:\n    def __init__(self, model_name, version, \n        replace_existing, wait_interval):\n        self._ml = MLEngineClient()\n        self._model_name = model_name\n        self._project_id, self._model_id = self._parse_model_name(model_name)\n        # The name of the version resource, which is in the format \n        # of projects/*/models/*/versions/*\n        self._version_name = None\n        # The user provide short name of the version.\n        self._version_id = None\n        # The full payload of the version resource.\n        self._version = version\n        self._replace_existing = replace_existing\n        self._wait_interval = wait_interval\n        self._create_operation_name = None\n        self._delete_operation_name = None\n\n    def execute_and_wait(self):\n        with KfpExecutionContext(on_cancel=self._cancel) as ctx:\n            self._set_version_name(ctx.context_id())\n            self._dump_metadata()\n            existing_version = wait_existing_version(self._ml, \n                self._version_name, \n                self._wait_interval)\n            if existing_version and self._is_dup_version(existing_version):\n                return self._handle_completed_version(existing_version)\n\n            if existing_version and self._replace_existing:\n                logging.info('Deleting existing version...')\n                self._delete_version_and_wait()\n            elif existing_version:\n                raise RuntimeError(\n                    'Existing version conflicts with the name of the new version.')\n            \n            created_version = self._create_version_and_wait()\n            return self._handle_completed_version(created_version)\n    \n    def _parse_model_name(self, model_name):\n        match = re.search(r'^projects/([^/]+)/models/([^/]+)$', model_name)\n        if not match:\n            raise ValueError('model name \"{}\" is not in desired format.'.format(model_name))\n        return (match.group(1), match.group(2))\n\n    def _set_version_name(self, context_id):\n        name = self._version.get('name', None)\n        if not name:\n            name = 'ver_' + context_id\n        name = gcp_common.normalize_name(name)\n        self._version_id = name\n        self._version['name'] = name\n        self._version_name = '{}/versions/{}'.format(self._model_name, name)\n\n    def _cancel(self):\n        if self._delete_operation_name:\n            self._ml.cancel_operation(self._delete_operation_name)\n\n        if self._create_operation_name:\n            self._ml.cancel_operation(self._create_operation_name)\n\n    def _create_version_and_wait(self):\n        operation = self._ml.create_version(self._model_name, self._version)\n        # Cache operation name for cancellation.\n        self._create_operation_name = operation.get('name')\n        try:\n            operation = wait_for_operation_done(\n                self._ml,\n                self._create_operation_name, \n                'create version',\n                self._wait_interval)\n        finally:\n            self._create_operation_name = None\n        return operation.get('response', None)\n\n    def _delete_version_and_wait(self):\n        operation = self._ml.delete_version(self._version_name)\n        # Cache operation name for cancellation.\n        self._delete_operation_name = operation.get('name')\n        try:\n            wait_for_operation_done(\n                self._ml,\n                self._delete_operation_name, \n                'delete version',\n                self._wait_interval)\n        finally:\n            self._delete_operation_name = None\n        \n    def _handle_completed_version(self, version):\n        state = version.get('state', None)\n        if state == 'FAILED':\n            error_message = version.get('errorMessage', 'Unknown failure')\n            raise RuntimeError('Version is in failed state: {}'.format(\n                error_message))\n        # Workaround issue that CMLE doesn't return the full version name.\n        version['name'] = self._version_name\n        self._dump_version(version)\n        return version\n\n    def _dump_metadata(self):\n        display.display(display.Link(\n            'https://console.cloud.google.com/mlengine/models/{}/versions/{}?project={}'.format(\n                self._model_id, self._version_id, self._project_id),\n            'Version Details'\n        ))\n        display.display(display.Markdown('''\n## Online Prediction\n\n### REST endpoint\nThe REST endpoint for online prediction is as follows:\n```\nPOST https://ml.googleapis.com/v1/{}:predict\n```\nTry the REST endpoint in [Google OAuth 2.0 Playgound](https://developers.google.com/oauthplayground/#step3\\\n&apisSelect=https://www.googleapis.com/auth/cloud-platform&postData={{\"instances\":[]}}\\\n&url=https://ml.googleapis.com/v1/{}:predict&content_type=application/json&http_method=POST).\n\n### GCloud command\n```bash\ngcloud ai-platform predict --model {}  \\\n                   --version {} \\\n                   --json-instances instances.json\n```\n        '''.format(self._version_name, self._version_name, self._model_id, self._version_id)))\n\n    def _dump_version(self, version):\n        logging.info('Dumping version: {}'.format(version))\n        gcp_common.dump_file('/tmp/kfp/output/ml_engine/version.json', json.dumps(version))\n        gcp_common.dump_file('/tmp/kfp/output/ml_engine/version_name.txt', version['name'])\n\n    def _is_dup_version(self, existing_version):\n        return not gcp_common.check_resource_changed(\n            self._version,\n            existing_version,\n            ['description', 'deploymentUri', \n                'runtimeVersion', 'machineType', 'labels',\n                'framework', 'pythonVersion', 'autoScaling',\n                'manualScaling'])\n", "path": "components/gcp/container/component_sdk/python/kfp_component/google/ml_engine/_create_version.py"}]}