Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use noun aliasing in kfp cli
Browse files Browse the repository at this point in the history
connor-mccarthy committed Apr 18, 2022
1 parent 5aaf6a4 commit 6ab2469
Showing 6 changed files with 168 additions and 13 deletions.
10 changes: 1 addition & 9 deletions sdk/python/kfp/cli/__main__.py
Original file line number Diff line number Diff line change
@@ -16,19 +16,11 @@
import sys

import click
import typer
from kfp.cli import (cli, components, diagnose_me_cli, experiment, pipeline,
recurring_run, run)
from kfp.cli import cli


def main():
logging.basicConfig(format='%(message)s', level=logging.INFO)
cli.cli.add_command(run.run)
cli.cli.add_command(recurring_run.recurring_run)
cli.cli.add_command(pipeline.pipeline)
cli.cli.add_command(diagnose_me_cli.diagnose_me)
cli.cli.add_command(experiment.experiment)
cli.cli.add_command(typer.main.get_command(components.app))
try:
cli.cli(obj={}, auto_envvar_prefix='KFP')
except Exception as e:
26 changes: 22 additions & 4 deletions sdk/python/kfp/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2018 The Kubeflow Authors
# Copyright 2018-2022 The Kubeflow Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,11 +13,29 @@
# limitations under the License.

import click
import typer
from kfp.cli import components
from kfp.cli import diagnose_me_cli
from kfp.cli import experiment
from kfp.cli import pipeline
from kfp.cli import recurring_run
from kfp.cli import run
from kfp.cli.output import OutputFormat
from kfp.cli.utils import aliased_plurals_group
from kfp.client import Client

COMMANDS = [
run.run,
recurring_run.recurring_run,
experiment.experiment,
pipeline.pipeline,
diagnose_me_cli.diagnose_me,
# typer.main.get_command(components.app)
]

@click.group()

@click.group(cls=aliased_plurals_group.AliasedPluralsGroup, commands=COMMANDS)
@click.pass_context
@click.option('--endpoint', help='Endpoint of the KFP API service to connect.')
@click.option('--iap-client-id', help='Client ID for IAP protected endpoint.')
@click.option(
@@ -38,19 +56,19 @@
default=OutputFormat.table.name,
show_default=True,
help='The formatting style for command output.')
@click.pass_context
def cli(ctx: click.Context, endpoint: str, iap_client_id: str, namespace: str,
other_client_id: str, other_client_secret: str, output: OutputFormat):
"""kfp is the command line interface to KFP service.
Feature stage:
[Alpha](https://github.com/kubeflow/pipelines/blob/07328e5094ac2981d3059314cc848fbb71437a76/docs/release/feature-stages.md#alpha)
"""
print("CONTEXT", ctx)
NO_CLIENT_COMMANDS = ['diagnose_me', 'components']
if ctx.invoked_subcommand in NO_CLIENT_COMMANDS:
# Do not create a client for these subcommands
return
ctx.obj['client'] = Client(endpoint, iap_client_id, namespace,
other_client_id, other_client_secret)
ctx.obj['namespace'] = namespace
ctx.obj['output'] = output
ctx.obj['output'] = output
40 changes: 40 additions & 0 deletions sdk/python/kfp/cli/cli_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2022 The Kubeflow Authors
#
# Licensed 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 functools
import unittest

from click import testing
from kfp.cli import cli


class TestCli(unittest.TestCase):

def setUp(self):
runner = testing.CliRunner()
self.invoke = functools.partial(
runner.invoke, cli=cli.cli, catch_exceptions=False, obj={})

def test_aliases_singular(self):
result = self.invoke(args=["run"])
self.assertEqual(result.exit_code, 0)

def test_aliases_plural(self):
result = self.invoke(args=["runs"])
self.assertEqual(result.exit_code, 0)

def test_aliases_fails(self):
result = self.invoke(args=["runss"])
self.assertEqual(result.exit_code, 2)
self.assertEqual("Error: Unrecognized command 'runss'\n", result.output)
13 changes: 13 additions & 0 deletions sdk/python/kfp/cli/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2022 The Kubeflow Authors
#
# Licensed 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.
37 changes: 37 additions & 0 deletions sdk/python/kfp/cli/utils/aliased_plurals_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2022 The Kubeflow Authors
#
# Licensed 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.

from typing import List, Tuple, Union

import click


class AliasedPluralsGroup(click.Group):

def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command:
regular = click.Group.get_command(self, ctx, cmd_name)
if regular is not None:
return regular
elif cmd_name.endswith("s"):
singular = click.Group.get_command(self, ctx, cmd_name[:-1])
if singular is not None:
return singular
raise click.UsageError(f"Unrecognized command '{cmd_name}'")

def resolve_command(
self, ctx: click.Context, args: List[str]
) -> Tuple[Union[str, None], Union[click.Command, None], List[str]]:
# always return the full command name
_, cmd, args = super().resolve_command(ctx, args)
return cmd.name, cmd, args # type: ignore
55 changes: 55 additions & 0 deletions sdk/python/kfp/cli/utils/aliased_plurals_group_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright 2022 The Kubeflow Authors
#
# Licensed 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 unittest

import click
from click import testing
from kfp.cli.utils import aliased_plurals_group


@click.group(cls=aliased_plurals_group.AliasedPluralsGroup)
def cli():
pass


@cli.command()
def command():
click.echo('Called command.')


class TestAliasedPluralsGroup(unittest.TestCase):

def setUp(self):
self.runner = testing.CliRunner()

def test_aliases_default_success(self):
result = self.runner.invoke(cli, ['command'])
self.assertEqual(result.exit_code, 0)
self.assertEqual(result.output, "Called command.\n")

def test_aliases_plural_success(self):
result = self.runner.invoke(cli, ['commands'])
self.assertEqual(result.exit_code, 0)
self.assertEqual(result.output, "Called command.\n")

def test_aliases_failure(self):
result = self.runner.invoke(cli, ['commandss'])
self.assertEqual(result.exit_code, 2)
self.assertEqual("Error: Unrecognized command 'commandss'\n",
result.output)


if __name__ == "__main__":
unittest.main()

0 comments on commit 6ab2469

Please sign in to comment.