Skip to content
This repository was archived by the owner on Aug 11, 2020. It is now read-only.

Commit 226df4b

Browse files
committed
Change output messages for experiment commands
1 parent 1960d6b commit 226df4b

File tree

8 files changed

+328
-37
lines changed

8 files changed

+328
-37
lines changed

Pipfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ botocore = "*"
1212
six = "*"
1313
gradient-statsd = "*"
1414
click = "*"
15+
terminaltables = "*"
1516

1617
[dev-packages]
1718
twine = "*"
1819
pypandoc = "*"
1920
pytest = "*"
21+
mock = "*"

paperspace/cli.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ def convert(self, value, param, ctx):
1919

2020

2121
MULTI_NODE_EXPERIMENT_TYPES_MAP = {
22-
"GRPC": constants.EXPERIMENT_TYPE_GRPC_MULTI_NODE_ID,
23-
"MPI": constants.EXPERIMENT_TYPE_MPI_MULTI_NODE_ID,
22+
"GRPC": constants.ExperimentType.GRPC_MULTI_NODE,
23+
"MPI": constants.ExperimentType.MPI_MULTI_NODE,
2424
}
2525

2626

@@ -225,33 +225,33 @@ def common_experiments_create_single_node_options(f):
225225
@common_experiment_create_multi_node_options
226226
def create_multi_node(**kwargs):
227227
del_if_value_is_none(kwargs)
228-
commands.create_experiments(kwargs)
228+
commands.create_experiment(kwargs)
229229

230230

231231
@create.command(name="singlenode")
232232
@common_experiments_create_options
233233
@common_experiments_create_single_node_options
234234
def create_single_node(**kwargs):
235-
kwargs["experimentTypeId"] = constants.EXPERIMENT_TYPE_SINGLE_NODE_ID
235+
kwargs["experimentTypeId"] = constants.ExperimentType.SINGLE_NODE
236236
del_if_value_is_none(kwargs)
237-
commands.create_experiments(kwargs)
237+
commands.create_experiment(kwargs)
238238

239239

240240
@create_and_start.command(name="multinode")
241241
@common_experiments_create_options
242242
@common_experiment_create_multi_node_options
243243
def create_and_start_multi_node(**kwargs):
244244
del_if_value_is_none(kwargs)
245-
commands.create_and_start_experiments(kwargs)
245+
commands.create_and_start_experiment(kwargs)
246246

247247

248248
@create_and_start.command(name="singlenode")
249249
@common_experiments_create_options
250250
@common_experiments_create_single_node_options
251251
def create_and_start_single_node(**kwargs):
252-
kwargs["experimentTypeId"] = constants.EXPERIMENT_TYPE_SINGLE_NODE_ID
252+
kwargs["experimentTypeId"] = constants.ExperimentType.SINGLE_NODE
253253
del_if_value_is_none(kwargs)
254-
commands.create_and_start_experiments(kwargs)
254+
commands.create_and_start_experiment(kwargs)
255255

256256

257257
@experiments.command()

paperspace/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ def post(self, url, json=None, params=None):
2222

2323
def put(self, url):
2424
path = self.get_path(url)
25-
logger.debug("Sending PUT to {}".format(path))
25+
logger.debug("Sending PUT to {}\nwith headers: {}".format(path, self.headers))
2626
response = requests.put(path, headers=self.headers)
2727
logger.debug("Response content: {}".format(response.content))
2828
return response
2929

3030
def get(self, url):
3131
path = self.get_path(url)
32-
logger.debug("Sending GET to {}".format(path))
32+
logger.debug("Sending GET to {}\nwith headers: {}".format(path, self.headers))
3333
response = requests.get(path, headers=self.headers)
3434
logger.debug("Response content: {}".format(response.content))
3535
return response

paperspace/commands.py

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from pprint import pformat
1+
import terminaltables
22

3-
from paperspace import version, logger
3+
from paperspace import version, logger, constants
44
from paperspace.client import API
55
from paperspace.config import config
66

@@ -11,42 +11,130 @@
1111
experiments_api = API(config.CONFIG_EXPERIMENTS_HOST, headers=default_headers)
1212

1313

14-
def _log_response(response, success_msg, error_msg):
14+
def _log_response(response, success_msg, error_msg, logger_=logger):
1515
if response.ok:
16-
logger.log(success_msg)
16+
logger_.log(success_msg)
1717
else:
1818
try:
1919
data = response.json()
20-
logger.log_error_response(data)
20+
logger_.log_error_response(data)
2121
except ValueError:
22-
logger.log(error_msg)
22+
logger_.log(error_msg)
2323

2424

25-
def create_experiments(json, api=experiments_api):
26-
response = api.post("/experiments/", json=json)
27-
_log_response(response, "Experiment created", "Unknown error while creating experiment")
25+
def _log_create_experiment(response, success_msg_template, error_msg, logger_=logger):
26+
if response.ok:
27+
j = response.json()
28+
handle = j["handle"]
29+
msg = success_msg_template.format(handle)
30+
logger_.log(msg)
31+
else:
32+
try:
33+
data = response.json()
34+
logger_.log_error_response(data)
35+
except ValueError:
36+
logger_.log(error_msg)
2837

2938

30-
def create_and_start_experiments(json, api=experiments_api):
31-
response = api.post("/experiments/create_and_start/", json=json)
32-
_log_response(response, "Experiment created", "Unknown error while creating experiment")
39+
def create_experiment(json_, api=experiments_api):
40+
response = api.post("/experiments/", json=json_)
41+
42+
_log_create_experiment(response,
43+
"New experiment created with handle: {}",
44+
"Unknown error while creating the experiment")
45+
46+
47+
def create_and_start_experiment(json_, api=experiments_api):
48+
response = api.post("/experiments/create_and_start/", json=json_)
49+
_log_create_experiment(response,
50+
"New experiment created and started with handle: {}",
51+
"Unknown error while creating/starting the experiment")
3352

3453

3554
def start_experiment(experiment_handle, api=experiments_api):
3655
url = "/experiments/{}/start/".format(experiment_handle)
3756
response = api.put(url)
38-
_log_response(response, "Experiment started", "Unknown error while starting experiment")
57+
_log_response(response, "Experiment started", "Unknown error while starting the experiment")
3958

4059

4160
def stop_experiment(experiment_handle, api=experiments_api):
4261
url = "/experiments/{}/stop/".format(experiment_handle)
4362
response = api.put(url)
44-
_log_response(response, "Experiment stopped", "Unknown error while stopping experiment")
63+
_log_response(response, "Experiment stopped", "Unknown error while stopping the experiment")
64+
65+
66+
def _make_experiments_list_table(experiments):
67+
data = [("Name", "Handle", "Status")]
68+
for experiment in experiments:
69+
name = experiment["templateHistory"]["params"]["name"]
70+
handle = experiment["handle"]
71+
status = constants.ExperimentState.get_state_str(experiment["state"])
72+
data.append((name, handle, status))
73+
74+
ascii_table = terminaltables.AsciiTable(data)
75+
table_string = ascii_table.table
76+
return table_string
4577

4678

4779
def list_experiments(api=experiments_api):
4880
response = api.get("/experiments/")
49-
_log_response(response, "Experiment stopped", "Unknown error while stopping experiment")
81+
details = response.content
82+
if response.ok:
83+
try:
84+
experiments = response.json()["data"]
85+
details = _make_experiments_list_table(experiments)
86+
except (ValueError, KeyError) as e:
87+
logger.log("Error parsing response data")
88+
logger.debug(e)
89+
90+
_log_response(response, details, "Unknown error while retrieving list of experiments")
91+
92+
93+
def _make_details_table(experiment):
94+
if experiment["experimentTypeId"] == constants.ExperimentType.SINGLE_NODE:
95+
data = (
96+
("Name", experiment["templateHistory"]["params"].get("name")),
97+
("Handle", experiment.get("handle")),
98+
("State", constants.ExperimentState.get_state_str(experiment.get("state"))),
99+
("Ports", experiment["templateHistory"]["params"].get("ports")),
100+
("Project Handle", experiment["templateHistory"]["params"].get("project_handle")),
101+
("Worker Command", experiment["templateHistory"]["params"].get("worker_command")),
102+
("Worker Container", experiment["templateHistory"]["params"].get("worker_container")),
103+
("Worker Machine Type", experiment["templateHistory"]["params"].get("worker_machine_type")),
104+
("Working Directory", experiment["templateHistory"]["params"].get("workingDirectory")),
105+
("Workspace URL", experiment["templateHistory"]["params"].get("workspaceUrl")),
106+
)
107+
elif experiment["experimentTypeId"] in (constants.ExperimentType.GRPC_MULTI_NODE,
108+
constants.ExperimentType.MPI_MULTI_NODE):
109+
data = (
110+
("Name", experiment["templateHistory"]["params"].get("name")),
111+
("Handle", experiment.get("handle")),
112+
("State", constants.ExperimentState.get_state_str(experiment.get("state"))),
113+
("Artifact directory", experiment["templateHistory"]["params"].get("artifactDirectory")),
114+
("Cluster ID", experiment["templateHistory"]["params"].get("clusterId")),
115+
("Experiment Env", experiment["templateHistory"]["params"].get("experimentEnv")),
116+
("Experiment Type",
117+
constants.ExperimentType.get_type_str(experiment["templateHistory"]["params"].get("experimentTypeId"))),
118+
("Parameter Server Command", experiment["templateHistory"]["params"].get("parameter_server_command")),
119+
("Parameter Server Container", experiment["templateHistory"]["params"].get("parameter_server_container")),
120+
("Parameter Server Count", experiment["templateHistory"]["params"].get("parameter_server_count")),
121+
("Parameter Server Machine Type",
122+
experiment["templateHistory"]["params"].get("parameter_server_machine_type")),
123+
("Ports", experiment["templateHistory"]["params"].get("ports")),
124+
("Project Handle", experiment["templateHistory"]["params"].get("project_handle")),
125+
("Worker Command", experiment["templateHistory"]["params"].get("worker_command")),
126+
("Worker Container", experiment["templateHistory"]["params"].get("worker_container")),
127+
("Worker Count", experiment["templateHistory"]["params"].get("worker_count")),
128+
("Worker Machine Type", experiment["templateHistory"]["params"].get("worker_machine_type")),
129+
("Working Directory", experiment["templateHistory"]["params"].get("workingDirectory")),
130+
("Workspace URL", experiment["templateHistory"]["params"].get("workspaceUrl")),
131+
)
132+
else:
133+
raise ValueError("Wrong experiment type: {}".format(experiment["experimentTypeId"]))
134+
135+
ascii_table = terminaltables.AsciiTable(data)
136+
table_string = ascii_table.table
137+
return table_string
50138

51139

52140
def get_experiment_details(experiment_handle, api=experiments_api):
@@ -55,7 +143,10 @@ def get_experiment_details(experiment_handle, api=experiments_api):
55143
details = response.content
56144
if response.ok:
57145
try:
58-
details = pformat(response.json()["data"][0])
59-
except (ValueError, KeyError, IndexError):
60-
pass
146+
experiment = response.json()["data"]
147+
details = _make_details_table(experiment)
148+
except (ValueError, KeyError) as e:
149+
logger.log("Error parsing response data")
150+
logger.debug(e)
151+
61152
_log_response(response, details, "Unknown error while retrieving details of the experiment")

paperspace/constants.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
1-
EXPERIMENT_TYPE_SINGLE_NODE_ID = 1
2-
EXPERIMENT_TYPE_GRPC_MULTI_NODE_ID = 2
3-
EXPERIMENT_TYPE_MPI_MULTI_NODE_ID = 3
1+
class ExperimentType:
2+
SINGLE_NODE = 1
3+
GRPC_MULTI_NODE = 2
4+
MPI_MULTI_NODE = 3
5+
6+
@classmethod
7+
def get_type_str(cls, state_int):
8+
type_strings = {
9+
1: "single node",
10+
2: "GRPC multi node",
11+
3: "MPI multi node",
12+
}
13+
return type_strings.get(state_int, "undefined")
14+
15+
16+
class ExperimentState:
17+
CREATED = 1
18+
PROVISIONED = 2
19+
NETWORK_SETUP = 3
20+
RUNNING = 4
21+
STOPPED = 5
22+
ERROR = 6
23+
FAILED = 7
24+
CANCELLED = 8
25+
NETWORK_TEARDOWN = 9
26+
PENDING = 10
27+
PROVISIONING = 11
28+
NETWORK_SETTING_UP = 12
29+
NETWORK_TEARING_DOWN = 13
30+
31+
@classmethod
32+
def get_state_str(cls, state_int):
33+
state_strings = {
34+
1: "created",
35+
2: "provisioned",
36+
3: "network setup",
37+
4: "running",
38+
5: "stopped",
39+
6: "error",
40+
7: "failed",
41+
8: "canceled",
42+
9: "network teardown",
43+
10: "pending",
44+
11: "provisioning",
45+
12: "network setting up",
46+
13: "network tearing down",
47+
}
48+
return state_strings.get(state_int, "undefined")

paperspace/logger.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
from .config import config
55

66

7-
def log(*messages, **kwargs):
7+
def log(message, **kwargs):
88
error = kwargs.get("error", False)
9-
for message in messages:
10-
click.echo(message, err=error)
9+
click.echo(message, err=error)
1110

1211

1312
def log_error_response(data):
@@ -33,6 +32,6 @@ def log_error_response(data):
3332
log(details)
3433

3534

36-
def debug(*messages):
35+
def debug(messages):
3736
if config.DEBUG:
38-
log(*messages)
37+
log("DEBUG: {}".format(messages))

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
],
4040
keywords='paperspace api development library',
4141
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
42-
install_requires=['requests[security]', 'boto3', 'botocore', 'six', 'gradient-statsd', 'click'],
42+
install_requires=['requests[security]', 'boto3', 'botocore', 'six', 'gradient-statsd', 'click', 'terminaltables'],
4343
entry_points={'console_scripts': [
4444
'paperspace-python = paperspace.main:main',
4545
]},

0 commit comments

Comments
 (0)