This is an automated email from the ASF dual-hosted git repository.

ztang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new c7bcdc0  SUBMARINE-527. [SDK] Abstract client API
c7bcdc0 is described below

commit c7bcdc0ec9de0e2f09b235f9c1e7ad26b33ace34
Author: pingsutw <[email protected]>
AuthorDate: Fri Jun 19 14:31:49 2020 +0800

    SUBMARINE-527. [SDK] Abstract client API
    
    ### What is this PR for?
    Try to simplify client API that generated by swagger, we could add an 
abstract layer on swagger API, and let users more easily submit experiments
    Also, prettify output in the notebook
    
    Before:  [Jupyter 
example](https://github.com/pingsutw/hadoop-submarine/blob/SUBMARINE-516/submarine-sdk/pysubmarine/example/submarine_experiment_sdk.ipynb)
    After: [Jupyter 
example](https://github.com/pingsutw/hadoop-submarine/blob/SUBMARINE-527/submarine-sdk/pysubmarine/example/submarine_experiment_sdk.ipynb)
    
    ### What type of PR is it?
    [Improvement]
    
    ### Todos
    * [ ] - e2e test
    * [ ] - unit test
    
    ### What is the Jira issue?
    
https://issues.apache.org/jira/browse/SUBMARINE-527?jql=project%20%3D%20SUBMARINE#
    
    ### How should this be tested?
    https://travis-ci.org/github/pingsutw/hadoop-submarine/builds/699648185
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: pingsutw <[email protected]>
    
    Closes #315 from pingsutw/SUBMARINE-527 and squashes the following commits:
    
    8b6e490 [pingsutw] Add wait_for_finish
    557b42e [pingsutw] Add todo
    545713f [pingsutw] Fix output
    bf135a9 [pingsutw] update iphnb
    dfb9c57 [pingsutw] remove submarine_experiment_sdk-checkpoint.ipynb
    a0cd247 [pingsutw] SUBMARINE-527. [SDK] Abstract client API
---
 .../example/submarine_experiment_sdk.ipynb         | 194 +++++++++++++++++----
 submarine-sdk/pysubmarine/submarine/__init__.py    |   4 +-
 .../submarine/experiment/api/experiment_client.py  | 140 +++++++++++++++
 3 files changed, 306 insertions(+), 32 deletions(-)

diff --git a/submarine-sdk/pysubmarine/example/submarine_experiment_sdk.ipynb 
b/submarine-sdk/pysubmarine/example/submarine_experiment_sdk.ipynb
index 9c1f5e2..efd9b87 100644
--- a/submarine-sdk/pysubmarine/example/submarine_experiment_sdk.ipynb
+++ b/submarine-sdk/pysubmarine/example/submarine_experiment_sdk.ipynb
@@ -11,7 +11,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 1,
    "metadata": {
     "pycharm": {
      "is_executing": false
@@ -20,9 +20,7 @@
    "outputs": [],
    "source": [
     "from __future__ import print_function\n",
-    "from submarine.experiment.configuration import Configuration\n",
-    "from submarine.experiment.api_client import ApiClient\n",
-    "from submarine.experiment.api.experiment_api import ExperimentApi\n",
+    "import submarine\n",
     "from submarine.experiment.models.environment import Environment\n",
     "from submarine.experiment.models.experiment_spec import ExperimentSpec\n",
     "from submarine.experiment.models.experiment_task_spec import 
ExperimentTaskSpec\n",
@@ -38,7 +36,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 2,
    "metadata": {
     "pycharm": {
      "is_executing": false,
@@ -47,10 +45,7 @@
    },
    "outputs": [],
    "source": [
-    "configuration = Configuration()\n",
-    "configuration.host = 'http://192.168.103.9:8080/api'\n",
-    "api_client = ApiClient(configuration=configuration)\n",
-    "submarine_client = ExperimentApi(api_client=api_client)"
+    "submarine_client = 
submarine.ExperimentClient(host='http://submarine:8080')"
    ]
   },
   {
@@ -68,7 +63,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 3,
    "metadata": {
     "pycharm": {
      "is_executing": false,
@@ -104,7 +99,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 4,
    "metadata": {
     "pycharm": {
      "name": "#%%\n",
@@ -115,15 +110,16 @@
    "outputs": [
     {
      "data": {
-      "text/plain": "{'attributes': {},\n 'code': 200,\n 'result': 
{'acceptedTime': '2020-06-18T08:25:14.000+08:00',\n            'createdTime': 
None,\n            'experimentId': 'experiment_1592409071112_0002',\n           
 'finishedTime': None,\n            'name': 'mnist',\n            
'runningTime': None,\n            'spec': {'environment': {'image': 
'gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0'},\n                     
'meta': {'cmd': 'python '\n                                  [...]
+      "text/plain": "{'experimentId': 'experiment_1592480334465_0001',\n 
'name': 'mnist',\n 'uid': '47f62be1-9d5a-473b-bac2-a7d40c365b45',\n 'status': 
'Accepted',\n 'acceptedTime': '2020-06-18T19:39:54.000+08:00',\n 'createdTime': 
None,\n 'runningTime': None,\n 'finishedTime': None,\n 'spec': {'meta': 
{'name': 'mnist',\n   'namespace': 'submarine',\n   'framework': 
'Tensorflow',\n   'cmd': 'python /var/tf_mnist/mnist_with_summaries.py 
--log_dir=/train/log --learning_rate=0.01 --batch_siz [...]
      },
      "metadata": {},
      "output_type": "execute_result",
-     "execution_count": 24
+     "execution_count": 4
     }
    ],
    "source": [
-    "submarine_client.create_experiment(experiment_spec=experiment_spec)"
+    "experiment = 
submarine_client.create_experiment(experiment_spec=experiment_spec)\n",
+    "experiment"
    ]
   },
   {
@@ -135,7 +131,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 5,
    "metadata": {
     "pycharm": {
      "name": "#%%\n",
@@ -145,15 +141,15 @@
    "outputs": [
     {
      "data": {
-      "text/plain": "{'attributes': {},\n 'code': 200,\n 'result': 
{'acceptedTime': '2020-06-18T08:25:14.000+08:00',\n            'createdTime': 
'2020-06-18T08:25:14.000+08:00',\n            'experimentId': 
'experiment_1592409071112_0002',\n            'finishedTime': None,\n           
 'name': 'mnist',\n            'runningTime': 
'2020-06-18T08:25:16.000+08:00',\n            'spec': {'environment': {'image': 
'gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0'},\n                     'meta' 
[...]
+      "text/plain": "{'experimentId': 'experiment_1592480334465_0001',\n 
'name': 'mnist',\n 'uid': '47f62be1-9d5a-473b-bac2-a7d40c365b45',\n 'status': 
'Running',\n 'acceptedTime': '2020-06-18T19:39:54.000+08:00',\n 'createdTime': 
'2020-06-18T19:39:54.000+08:00',\n 'runningTime': 
'2020-06-18T19:39:55.000+08:00',\n 'finishedTime': None,\n 'spec': {'meta': 
{'name': 'mnist',\n   'namespace': 'submarine',\n   'framework': 
'Tensorflow',\n   'cmd': 'python /var/tf_mnist/mnist_with_summaries.py  [...]
      },
      "metadata": {},
      "output_type": "execute_result",
-     "execution_count": 26
+     "execution_count": 5
     }
    ],
    "source": [
-    "id = 'experiment_1592409071112_0002'\n",
+    "id = experiment['experimentId']\n",
     "submarine_client.get_experiment(id)"
    ]
   },
@@ -166,7 +162,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 6,
    "metadata": {
     "pycharm": {
      "name": "#%%\n",
@@ -176,11 +172,11 @@
    "outputs": [
     {
      "data": {
-      "text/plain": "{'attributes': {},\n 'code': 200,\n 'result': 
[{'acceptedTime': '2020-06-18T08:25:14.000+08:00',\n             'createdTime': 
'2020-06-18T08:25:14.000+08:00',\n             'experimentId': 
'experiment_1592409071112_0002',\n             'finishedTime': None,\n          
   'name': 'mnist',\n             'runningTime': 
'2020-06-18T08:25:16.000+08:00',\n             'spec': {'environment': 
{'image': 'gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0'},\n                  
   [...]
+      "text/plain": "[{'experimentId': 'experiment_1592480334465_0001',\n  
'name': 'mnist',\n  'uid': '47f62be1-9d5a-473b-bac2-a7d40c365b45',\n  'status': 
'Running',\n  'acceptedTime': '2020-06-18T19:39:54.000+08:00',\n  
'createdTime': '2020-06-18T19:39:54.000+08:00',\n  'runningTime': 
'2020-06-18T19:39:55.000+08:00',\n  'finishedTime': None,\n  'spec': {'meta': 
{'name': 'mnist',\n    'namespace': 'submarine',\n    'framework': 
'Tensorflow',\n    'cmd': 'python /var/tf_mnist/mnist_with_s [...]
      },
      "metadata": {},
      "output_type": "execute_result",
-     "execution_count": 27
+     "execution_count": 6
     }
    ],
    "source": [
@@ -197,7 +193,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 9,
    "metadata": {
     "pycharm": {
      "name": "#%%\n",
@@ -206,12 +202,148 @@
    },
    "outputs": [
     {
-     "data": {
-      "text/plain": "{'attributes': {},\n 'code': 200,\n 'result': 
{'experimentId': 'experiment_1592409071112_0002',\n            'logContent': 
[{'podLog': ['WARNING:tensorflow:From '\n                                       
'/var/tf_mnist/mnist_with_summaries.py:39: '\n                                  
     'read_data_sets (from '\n                                       
'tensorflow.contrib.learn.python.learn.datasets.mnist) '\n                      
                 'is deprecated and wil [...]
-     },
-     "metadata": {},
-     "output_type": "execute_result",
-     "execution_count": 32
+     "name": "stderr",
+     "text": [
+      "The logs of Pod mnist-worker-0:\n\n",
+      "WARNING:tensorflow:From /var/tf_mnist/mnist_with_summaries.py:39: 
read_data_sets (from tensorflow.contrib.learn.python.learn.datasets.mnist) is 
deprecated and will be removed in a future version.\n",
+      "Instructions for updating:\n",
+      "Please use alternatives such as official/mnist/dataset.py from 
tensorflow/models.\n",
+      "WARNING:tensorflow:From 
/usr/local/lib/python2.7/dist-packages/tensorflow/contrib/learn/python/learn/datasets/mnist.py:260:
 maybe_download (from tensorflow.contrib.learn.python.learn.datasets.base) is 
deprecated and will be removed in a future version.\n",
+      "Instructions for updating:\n",
+      "Please write your own downloading logic.\n",
+      "WARNING:tensorflow:From 
/usr/local/lib/python2.7/dist-packages/tensorflow/contrib/learn/python/learn/datasets/base.py:252:
 wrapped_fn (from tensorflow.contrib.learn.python.learn.datasets.base) is 
deprecated and will be removed in a future version.\n",
+      "Instructions for updating:\n",
+      "Please use urllib or similar directly.\n",
+      "WARNING:tensorflow:From 
/usr/local/lib/python2.7/dist-packages/tensorflow/contrib/learn/python/learn/datasets/mnist.py:262:
 extract_images (from tensorflow.contrib.learn.python.learn.datasets.mnist) is 
deprecated and will be removed in a future version.\n",
+      "Instructions for updating:\n",
+      "Please use tf.data to implement this functionality.\n",
+      "WARNING:tensorflow:From 
/usr/local/lib/python2.7/dist-packages/tensorflow/contrib/learn/python/learn/datasets/mnist.py:267:
 extract_labels (from tensorflow.contrib.learn.python.learn.datasets.mnist) is 
deprecated and will be removed in a future version.\n",
+      "Instructions for updating:\n",
+      "Please use tf.data to implement this functionality.\n",
+      "WARNING:tensorflow:From 
/usr/local/lib/python2.7/dist-packages/tensorflow/contrib/learn/python/learn/datasets/mnist.py:290:
 __init__ (from tensorflow.contrib.learn.python.learn.datasets.mnist) is 
deprecated and will be removed in a future version.\n",
+      "Instructions for updating:\n",
+      "Please use alternatives such as official/mnist/dataset.py from 
tensorflow/models.\n",
+      "2020-06-18 11:39:58.166584: I 
tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports 
instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
+      "Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.\n",
+      "Extracting 
/tmp/tensorflow/mnist/input_data/train-images-idx3-ubyte.gz\n",
+      "Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.\n",
+      "Extracting 
/tmp/tensorflow/mnist/input_data/train-labels-idx1-ubyte.gz\n",
+      "Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.\n",
+      "Extracting 
/tmp/tensorflow/mnist/input_data/t10k-images-idx3-ubyte.gz\n",
+      "Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.\n",
+      "Extracting 
/tmp/tensorflow/mnist/input_data/t10k-labels-idx1-ubyte.gz\n",
+      "Accuracy at step 0: 0.0954\n",
+      "Accuracy at step 10: 0.6885\n",
+      "Accuracy at step 20: 0.8634\n",
+      "Accuracy at step 30: 0.8975\n",
+      "Accuracy at step 40: 0.9174\n",
+      "Accuracy at step 50: 0.9235\n",
+      "Accuracy at step 60: 0.9276\n",
+      "Accuracy at step 70: 0.9297\n",
+      "Accuracy at step 80: 0.9317\n",
+      "Accuracy at step 90: 0.9401\n",
+      "Adding run metadata for 99\n",
+      "Accuracy at step 100: 0.9389\n",
+      "Accuracy at step 110: 0.9426\n",
+      "Accuracy at step 120: 0.9467\n",
+      "Accuracy at step 130: 0.948\n",
+      "Accuracy at step 140: 0.9497\n",
+      "Accuracy at step 150: 0.9514\n",
+      "Accuracy at step 160: 0.9534\n",
+      "Accuracy at step 170: 0.9464\n",
+      "Accuracy at step 180: 0.9494\n",
+      "Accuracy at step 190: 0.9496\n",
+      "Adding run metadata for 199\n",
+      "Accuracy at step 200: 0.9503\n",
+      "Accuracy at step 210: 0.9537\n",
+      "Accuracy at step 220: 0.953\n",
+      "Accuracy at step 230: 0.9521\n",
+      "Accuracy at step 240: 0.959\n",
+      "Accuracy at step 250: 0.9579\n",
+      "Accuracy at step 260: 0.9546\n",
+      "Accuracy at step 270: 0.9518\n",
+      "Accuracy at step 280: 0.958\n",
+      "Accuracy at step 290: 0.9598\n",
+      "Adding run metadata for 299\n",
+      "Accuracy at step 300: 0.9578\n",
+      "Accuracy at step 310: 0.9622\n",
+      "Accuracy at step 320: 0.9654\n",
+      "Accuracy at step 330: 0.9588\n",
+      "Accuracy at step 340: 0.9605\n",
+      "Accuracy at step 350: 0.9626\n",
+      "Accuracy at step 360: 0.9561\n",
+      "Accuracy at step 370: 0.9647\n",
+      "Accuracy at step 380: 0.9659\n",
+      "Accuracy at step 390: 0.9618\n",
+      "Adding run metadata for 399\n",
+      "Accuracy at step 400: 0.9621\n",
+      "Accuracy at step 410: 0.9642\n",
+      "Accuracy at step 420: 0.9652\n",
+      "Accuracy at step 430: 0.9647\n",
+      "Accuracy at step 440: 0.9642\n",
+      "Accuracy at step 450: 0.9648\n",
+      "Accuracy at step 460: 0.9652\n",
+      "Accuracy at step 470: 0.965\n",
+      "Accuracy at step 480: 0.9659\n",
+      "Accuracy at step 490: 0.9615\n",
+      "Adding run metadata for 499\n",
+      "Accuracy at step 500: 0.9599\n",
+      "Accuracy at step 510: 0.9648\n",
+      "Accuracy at step 520: 0.9654\n",
+      "Accuracy at step 530: 0.9576\n",
+      "Accuracy at step 540: 0.9664\n",
+      "Accuracy at step 550: 0.9661\n",
+      "Accuracy at step 560: 0.9694\n",
+      "Accuracy at step 570: 0.97\n",
+      "Accuracy at step 580: 0.9668\n",
+      "Accuracy at step 590: 0.9667\n",
+      "Adding run metadata for 599\n",
+      "Accuracy at step 600: 0.9675\n",
+      "Accuracy at step 610: 0.9685\n",
+      "Accuracy at step 620: 0.9692\n",
+      "Accuracy at step 630: 0.9695\n",
+      "Accuracy at step 640: 0.9657\n",
+      "Accuracy at step 650: 0.9648\n",
+      "Accuracy at step 660: 0.9707\n",
+      "Accuracy at step 670: 0.9689\n",
+      "Accuracy at step 680: 0.9716\n",
+      "Accuracy at step 690: 0.9698\n",
+      "Adding run metadata for 699\n",
+      "Accuracy at step 700: 0.9667\n",
+      "Accuracy at step 710: 0.9632\n",
+      "Accuracy at step 720: 0.9678\n",
+      "Accuracy at step 730: 0.9664\n",
+      "Accuracy at step 740: 0.9688\n",
+      "Accuracy at step 750: 0.9662\n",
+      "Accuracy at step 760: 0.9705\n",
+      "Accuracy at step 770: 0.9686\n",
+      "Accuracy at step 780: 0.9692\n",
+      "Accuracy at step 790: 0.9662\n",
+      "Adding run metadata for 799\n",
+      "Accuracy at step 800: 0.9619\n",
+      "Accuracy at step 810: 0.9667\n",
+      "Accuracy at step 820: 0.968\n",
+      "Accuracy at step 830: 0.9688\n",
+      "Accuracy at step 840: 0.9707\n",
+      "Accuracy at step 850: 0.9726\n",
+      "Accuracy at step 860: 0.9716\n",
+      "Accuracy at step 870: 0.9708\n",
+      "Accuracy at step 880: 0.9707\n",
+      "Accuracy at step 890: 0.9672\n",
+      "Adding run metadata for 899\n",
+      "Accuracy at step 900: 0.9601\n",
+      "Accuracy at step 910: 0.9664\n",
+      "Accuracy at step 920: 0.9665\n",
+      "Accuracy at step 930: 0.9695\n",
+      "Accuracy at step 940: 0.969\n",
+      "Accuracy at step 950: 0.9677\n",
+      "Accuracy at step 960: 0.9688\n",
+      "Accuracy at step 970: 0.9576\n",
+      "Accuracy at step 980: 0.9547\n",
+      "Accuracy at step 990: 0.9679\n",
+      "Adding run metadata for 999\n"
+     ],
+     "output_type": "stream"
     }
    ],
    "source": [
@@ -227,7 +359,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 10,
    "metadata": {
     "pycharm": {
      "name": "#%%\n",
@@ -237,11 +369,11 @@
    "outputs": [
     {
      "data": {
-      "text/plain": "{'attributes': {},\n 'code': 200,\n 'result': 
{'acceptedTime': '2020-06-18T08:25:14.000+08:00',\n            'createdTime': 
'2020-06-18T08:25:14.000+08:00',\n            'experimentId': 
'experiment_1592409071112_0002',\n            'finishedTime': 
'2020-06-18T08:29:02.000+08:00',\n            'name': 'mnist',\n            
'runningTime': '2020-06-18T08:25:16.000+08:00',\n            'spec': 
{'environment': {'image': 'gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0'},\n 
[...]
+      "text/plain": "{'experimentId': 'experiment_1592480334465_0001',\n 
'name': 'mnist',\n 'uid': '47f62be1-9d5a-473b-bac2-a7d40c365b45',\n 'status': 
'Deleted',\n 'acceptedTime': '2020-06-18T19:39:54.000+08:00',\n 'createdTime': 
'2020-06-18T19:39:54.000+08:00',\n 'runningTime': 
'2020-06-18T19:39:55.000+08:00',\n 'finishedTime': 
'2020-06-18T19:43:23.000+08:00',\n 'spec': {'meta': {'name': 'mnist',\n   
'namespace': 'submarine',\n   'framework': 'Tensorflow',\n   'cmd': 'python 
/var/tf_mni [...]
      },
      "metadata": {},
      "output_type": "execute_result",
-     "execution_count": 33
+     "execution_count": 10
     }
    ],
    "source": [
diff --git a/submarine-sdk/pysubmarine/submarine/__init__.py 
b/submarine-sdk/pysubmarine/submarine/__init__.py
index 2f11da9..a23de5b 100644
--- a/submarine-sdk/pysubmarine/submarine/__init__.py
+++ b/submarine-sdk/pysubmarine/submarine/__init__.py
@@ -15,6 +15,7 @@
 
 import submarine.tracking as tracking
 import submarine.tracking.fluent
+from submarine.experiment.api.experiment_client import ExperimentClient
 
 log_param = submarine.tracking.fluent.log_param
 log_metric = submarine.tracking.fluent.log_metric
@@ -24,5 +25,6 @@ get_tracking_uri = tracking.get_tracking_uri
 __all__ = ["log_metric",
            "log_param",
            "set_tracking_uri",
-           "get_tracking_uri"
+           "get_tracking_uri",
+           "ExperimentClient"
            ]
diff --git 
a/submarine-sdk/pysubmarine/submarine/experiment/api/experiment_client.py 
b/submarine-sdk/pysubmarine/submarine/experiment/api/experiment_client.py
new file mode 100644
index 0000000..0a176cf
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/experiment/api/experiment_client.py
@@ -0,0 +1,140 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+import logging
+import time
+
+from submarine.experiment.configuration import Configuration
+from submarine.experiment.api_client import ApiClient
+from submarine.experiment.api.experiment_api import ExperimentApi
+
+logger = logging.getLogger(__name__)
+logging.basicConfig(format='%(message)s')
+logging.getLogger().setLevel(logging.INFO)
+
+
+class ExperimentClient:
+    def __init__(self, host):
+        """
+        Submarine experiment client constructor
+        :param host: An HTTP URI like http://submarine-server:8080.
+        """
+        # TODO(pingsutw): support authentication for talking to the submarine 
server
+        self.host = host
+        configuration = Configuration()
+        configuration.host = host + '/api'
+        api_client = ApiClient(configuration=configuration)
+        self.experiment_api = ExperimentApi(api_client=api_client)
+
+    def create_experiment(self, experiment_spec):
+        """
+        Create an experiment
+        :param experiment_spec: submarine experiment spec
+        :return: submarine experiment
+        """
+        response = 
self.experiment_api.create_experiment(experiment_spec=experiment_spec)
+        return response.result
+
+    def wait_for_finish(self, id, polling_interval=10):
+        """
+        Waits until experiment is finished or failed
+        :param id: submarine experiment id
+        :param polling_interval: How often to poll for the status of the 
experiment.
+        :return: str: experiment logs
+        """
+        index = 0
+        while True:
+            status = self.get_experiment(id)['status']
+            if status == 'Succeeded' or status == 'Deleted':
+                self._log_pod(id, index)
+                break
+            index = self._log_pod(id, index)
+            time.sleep(polling_interval)
+
+    def _log_pod(self, id, index):
+        response = self.experiment_api.get_log(id)
+        log_content = response.result['logContent'][0]
+        for i, log in enumerate(log_content['podLog']):
+            if i < index:
+                continue
+            index += 1
+            logging.info("%s", log)
+        return index
+
+    def patch_experiment(self, id, experiment_spec):
+        """
+        Patch an experiment
+        :param id: submarine experiment id
+        :param experiment_spec: submarine experiment spec
+        :return: submarine experiment
+        """
+        response = self.experiment_api.patch_experiment(id=id, 
experiment_spec=experiment_spec)
+        return response.result
+
+    def get_experiment(self, id):
+        """
+        Get the experiment's detailed info by id
+        :param id: submarine experiment id
+        :return: submarine experiment
+        """
+        response = self.experiment_api.get_experiment(id=id)
+        return response.result
+
+    def list_experiments(self, status):
+        """
+        List all experiment for the user
+        :param status: Accepted, Created, Running, Succeeded, Deleted
+        :return: List of submarine experiments
+        """
+        response = self.experiment_api.list_experiments(status=status)
+        return response.result
+
+    def delete_experiment(self, id):
+        """
+        Delete the Submarine experiment
+        :param id: Submarine experiment id
+        :return: The detailed info about deleted submarine experiment
+        """
+        response = self.experiment_api.delete_experiment(id)
+        return response.result
+
+    def get_log(self, id, master=True):
+        """
+        Get training logs of the experiment.
+        By default only get the logs of Pod that has labels 'job-role: master'.
+        :param master: By default get pod with label 'job-role: master' pod if 
True.
+                    If need to get more Pod Logs, set False.
+        :param id: Experiment ID
+        :return: str: experiment logs
+        """
+        response = self.experiment_api.get_log(id)
+        log_contents = response.result['logContent']
+
+        if master is True:
+            log_contents = [log_contents[0]]
+
+        for log_content in log_contents:
+            logging.info("The logs of Pod %s:\n", log_content['podName'])
+            for log in log_content['podLog']:
+                logging.info("%s", log)
+
+    def list_log(self, status):
+        """
+        List experiment log
+        :param status: Accepted, Created, Running, Succeeded, Deleted
+        :return: List of submarine log
+        """
+        response = self.experiment_api.list_log(status=status)
+        return response.result


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to