import click import json from typing import List from kfp.deprecated.cli.output import print_output, OutputFormat import kfp_server_api from kfp_server_api.models.api_experiment import ApiExperiment @click.group() def experiment(): """Manage experiment resources.""" @experiment.command() @click.option('-d', '--description', help="Description of the experiment.") @click.argument("name") @click.pass_context def create(ctx: click.Context, description: str, name: str): """Create an experiment.""" client = ctx.obj["client"] output_format = ctx.obj["output"] response = client.create_experiment(name, description=description) _display_experiment(response, output_format) @experiment.command() @click.option( '--page-token', default='', help="Token for starting of the page.") @click.option( '-m', '--max-size', default=100, help="Max size of the listed experiments.") @click.option( '--sort-by', default="created_at desc", help="Can be '[field_name]', '[field_name] desc'. For example, 'name desc'." ) @click.option( '--filter', help=( "filter: A url-encoded, JSON-serialized Filter protocol buffer " "(see [filter.proto](https://github.com/kubeflow/pipelines/blob/master/backend/api/filter.proto))." )) @click.pass_context def list(ctx: click.Context, page_token: str, max_size: int, sort_by: str, filter: str): """List experiments.""" client = ctx.obj['client'] output_format = ctx.obj['output'] response = client.list_experiments( page_token=page_token, page_size=max_size, sort_by=sort_by, filter=filter) if response.experiments: _display_experiments(response.experiments, output_format) else: if output_format == OutputFormat.json.name: msg = json.dumps([]) else: msg = "No experiments found" click.echo(msg) @experiment.command() @click.argument("experiment-id") @click.pass_context def get(ctx: click.Context, experiment_id: str): """Get detailed information about an experiment.""" client = ctx.obj["client"] output_format = ctx.obj["output"] response = client.get_experiment(experiment_id) _display_experiment(response, output_format) @experiment.command() @click.argument("experiment-id") @click.pass_context def delete(ctx: click.Context, experiment_id: str): """Delete an experiment.""" confirmation = "Caution. The RunDetails page could have an issue" \ " when it renders a run that has no experiment." \ " Do you want to continue?" if not click.confirm(confirmation): return client = ctx.obj["client"] client.delete_experiment(experiment_id) click.echo("{} is deleted.".format(experiment_id)) def _display_experiments(experiments: List[ApiExperiment], output_format: OutputFormat): headers = ["Experiment ID", "Name", "Created at"] data = [ [exp.id, exp.name, exp.created_at.isoformat()] for exp in experiments ] print_output(data, headers, output_format, table_format="grid") def _display_experiment(exp: kfp_server_api.ApiExperiment, output_format: OutputFormat): table = [ ["ID", exp.id], ["Name", exp.name], ["Description", exp.description], ["Created at", exp.created_at.isoformat()], ] if output_format == OutputFormat.table.name: print_output([], ["Experiment Details"], output_format) print_output(table, [], output_format, table_format="plain") elif output_format == OutputFormat.json.name: print_output(dict(table), [], output_format) @experiment.command() @click.option( "--experiment-id", default=None, help="The ID of the experiment to archive, can only supply either an experiment ID or name." ) @click.option( "--experiment-name", default=None, help="The name of the experiment to archive, can only supply either an experiment ID or name." ) @click.pass_context def archive(ctx: click.Context, experiment_id: str, experiment_name: str): """Archive an experiment.""" client = ctx.obj["client"] if (experiment_id is None) == (experiment_name is None): raise ValueError('Either experiment_id or experiment_name is required') if not experiment_id: experiment = client.get_experiment(experiment_name=experiment_name) experiment_id = experiment.id client.archive_experiment(experiment_id=experiment_id)