From 2df2dc6d4c4079cabf69cf1afad2c03234978f43 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Thu, 11 Jan 2018 14:33:41 -0800 Subject: [PATCH 1/5] do not use mutable objects for default arguments --- floyd/model/module.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/floyd/model/module.py b/floyd/model/module.py index 9c55400..5c4e818 100644 --- a/floyd/model/module.py +++ b/floyd/model/module.py @@ -27,8 +27,6 @@ def make_module(self, data): class Module(BaseModel): schema = ModuleSchema(strict=True) - default_outputs = [{'name': 'output', 'type': 'dir'}] - default_inputs = [{'name': 'input', 'type': 'dir'}] def __init__(self, name, @@ -39,8 +37,8 @@ def __init__(self, module_type="code", default_container=DEFAULT_DOCKER_IMAGE, family_id=None, - outputs=default_outputs, - inputs=default_inputs, + outputs=None, + inputs=None, env=DEFAULT_ENV, arch=DEFAULT_ARCH, resource_id=None,): @@ -52,8 +50,8 @@ def __init__(self, self.module_type = module_type self.default_container = default_container self.family_id = family_id - self.outputs = outputs - self.inputs = inputs + self.outputs = outputs if outputs else [{'name': 'output', 'type': 'dir'}] + self.inputs = inputs if inputs else [{'name': 'input', 'type': 'dir'}] self.env = env self.arch = arch self.resource_id = resource_id From 17e1cd866ed13aacff3787742239871ed33e0ab5 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Thu, 11 Jan 2018 14:34:10 -0800 Subject: [PATCH 2/5] =?UTF-8?q?Bump=20version:=200.10.29=20=E2=86=92=200.1?= =?UTF-8?q?0.30?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- conda/meta.yaml | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 1b96641..1cf01e5 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.10.29 +current_version = 0.10.30 commit = True tag = False diff --git a/conda/meta.yaml b/conda/meta.yaml index a6104f5..d6c247b 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,5 +1,5 @@ {% set name = "floyd-cli" %} -{% set version = "0.10.29" %} +{% set version = "0.10.30" %} {% set file_ext = "tar.gz" %} package: diff --git a/setup.py b/setup.py index 185c7ec..4f5812d 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import find_packages, setup project = "floyd-cli" -version = "0.10.29" +version = "0.10.30" with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme: long_description = readme.read() From 7b488b7a6dd9e3a370ff384b4a89855770fd39f9 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 16 Jan 2018 13:07:59 -0800 Subject: [PATCH 3/5] ux: display job URL at the end of job run Since jupyter url is the same as job URL, we can remove the code inside the jupyter branch --- floyd/cli/run.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/floyd/cli/run.py b/floyd/cli/run.py index 4dbd6c6..c076f2e 100644 --- a/floyd/cli/run.py +++ b/floyd/cli/run.py @@ -82,6 +82,12 @@ def validate_env(env, instance_type): def show_new_job_info(expt_client, job_name, expt_info, mode, open_notebook=True): + table_output = [["JOB NAME"], [job_name]] + floyd_logger.info('\n' + tabulate(table_output, headers="firstrow") + '\n') + + job_url = '%s/%s' % (floyd.floyd_web_host, job_name) + floyd_logger.info("URL to job: %s", job_url) + if mode in ['jupyter', 'serve']: while True: # Wait for the experiment / task instances to become available @@ -96,20 +102,18 @@ def show_new_job_info(expt_client, job_name, expt_info, mode, open_notebook=True sleep(3) continue - # Print the path to jupyter notebook + # Print the url to jupyter notebook if mode == 'jupyter': if not experiment.service_url: floyd_logger.error("Jupyter not available, please check job state and log for error.") sys.exit(1) - jupyter_url = '%s/%s' % (floyd.floyd_web_host, job_name) - floyd_logger.info("\nPath to jupyter notebook: %s", jupyter_url) if open_notebook: - webbrowser.open(jupyter_url) + webbrowser.open(job_url) - # Print the path to serving endpoint + # Print the url to serving endpoint if mode == 'serve': - floyd_logger.info("Path to service endpoint: %s", experiment.service_url) + floyd_logger.info("URL to service endpoint: %s", experiment.service_url) if experiment.timeout_seconds < 24 * 60 * 60: floyd_logger.info("\nYour job timeout is currently set to %s seconds", @@ -118,7 +122,7 @@ def show_new_job_info(expt_client, job_name, expt_info, mode, open_notebook=True "See https://www.floydhub.com/pricing for details") else: - floyd_logger.info("To view logs enter:") + floyd_logger.info("\nTo view logs enter:") floyd_logger.info(" floyd logs %s", job_name) @@ -244,10 +248,6 @@ def run(ctx, gpu, env, message, data, mode, open_notebook, tensorboard, gpup, cp floyd_logger.debug("Created job : %s", expt_info['id']) job_name = expt_info['name'] - floyd_logger.info("") - table_output = [["JOB NAME"], [job_name]] - floyd_logger.info(tabulate(table_output, headers="firstrow")) - floyd_logger.info("") show_new_job_info(expt_client, job_name, expt_info, mode, open_notebook) @@ -368,8 +368,4 @@ def restart(ctx, job_name, data, open_notebook, env, message, gpu, cpu, gpup, cp floyd_logger.error("Failed to restart job") sys.exit(1) - floyd_logger.info('New job created:') - table_output = [["JOB NAME"], [new_job_info['name']]] - floyd_logger.info('\n' + tabulate(table_output, headers="firstrow") + '\n') - show_new_job_info(expt_client, new_job_info['name'], new_job_info, job.mode, open_notebook) From 504a413f14fc194b9f672b2e4482092e6afbd9a7 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 16 Jan 2018 13:09:00 -0800 Subject: [PATCH 4/5] fix: update argument name for delete command --- floyd/cli/experiment.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/floyd/cli/experiment.py b/floyd/cli/experiment.py index ccb03d4..388702f 100644 --- a/floyd/cli/experiment.py +++ b/floyd/cli/experiment.py @@ -230,18 +230,18 @@ def stop(id): @click.command() -@click.argument('ids', nargs=-1) +@click.argument('names', nargs=-1) @click.option('-y', '--yes', is_flag=True, default=False, help='Skip confirmation') -def delete(ids, yes): +def delete(names, yes): """ Delete project runs """ failures = False - for id in ids: + for name in names: try: - experiment = ExperimentClient().get(normalize_job_name(id)) + experiment = ExperimentClient().get(normalize_job_name(name)) except FloydException: - experiment = ExperimentClient().get(id) + experiment = ExperimentClient().get(name) if not experiment: failures = True From db842849304b0a7971564543e6c768c28238be2a Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 16 Jan 2018 13:11:27 -0800 Subject: [PATCH 5/5] fix: do not read data config for info command --- floyd/cli/experiment.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/floyd/cli/experiment.py b/floyd/cli/experiment.py index 388702f..ae78a02 100644 --- a/floyd/cli/experiment.py +++ b/floyd/cli/experiment.py @@ -6,7 +6,7 @@ import floyd from floyd.cli.utils import ( - get_module_task_instance_id, normalize_job_name, normalize_data_name + get_module_task_instance_id, normalize_job_name ) from floyd.client.experiment import ExperimentClient from floyd.client.module import ModuleClient @@ -125,8 +125,9 @@ def info(job_name_or_id): task_instance_id = get_module_task_instance_id(experiment.task_instances) task_instance = TaskInstanceClient().get(task_instance_id) if task_instance_id else None - table = [["Job name", normalize_job_name(experiment.name)], - ["Output name", normalize_data_name(experiment.name + '/output') if task_instance else None], + normalized_job_name = normalize_job_name(experiment.name) + table = [["Job name", normalized_job_name], + ["Output name", normalized_job_name + '/output' if task_instance else None], ["Created", experiment.created_pretty], ["Status", experiment.state], ["Duration(s)", experiment.duration_rounded], ["Instance", experiment.instance_type_trimmed],