Return-Path: X-Original-To: apmail-aurora-commits-archive@minotaur.apache.org Delivered-To: apmail-aurora-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9C770106E0 for ; Fri, 7 Feb 2014 19:56:34 +0000 (UTC) Received: (qmail 55597 invoked by uid 500); 7 Feb 2014 19:56:29 -0000 Delivered-To: apmail-aurora-commits-archive@aurora.apache.org Received: (qmail 55348 invoked by uid 500); 7 Feb 2014 19:56:26 -0000 Mailing-List: contact commits-help@aurora.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@aurora.incubator.apache.org Delivered-To: mailing list commits@aurora.incubator.apache.org Received: (qmail 55188 invoked by uid 99); 7 Feb 2014 19:56:23 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 07 Feb 2014 19:56:22 +0000 X-ASF-Spam-Status: No, hits=-2000.5 required=5.0 tests=ALL_TRUSTED,RP_MATCHES_RCVD,T_FILL_THIS_FORM_SHORT X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO mail.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with SMTP; Fri, 07 Feb 2014 19:56:19 +0000 Received: (qmail 54380 invoked by uid 99); 7 Feb 2014 19:55:59 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 07 Feb 2014 19:55:59 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 85CED91F81B; Fri, 7 Feb 2014 19:55:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mchucarroll@apache.org To: commits@aurora.incubator.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: git commit: Bridge framework for client v2. (See AURORA-76) Date: Fri, 7 Feb 2014 19:55:59 +0000 (UTC) X-Virus-Checked: Checked by ClamAV on apache.org Updated Branches: refs/heads/master 4dcddab2f -> e6f415085 Bridge framework for client v2. (See AURORA-76) Reviewed in 17270. Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/e6f41508 Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/e6f41508 Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/e6f41508 Branch: refs/heads/master Commit: e6f415085d6fb066687e91fb3025c18f27df0ae4 Parents: 4dcddab Author: Mark Chu-Carroll Authored: Fri Feb 7 14:36:17 2014 -0500 Committer: Mark Chu-Carroll Committed: Fri Feb 7 14:36:17 2014 -0500 ---------------------------------------------------------------------- src/main/python/apache/aurora/client/bin/BUILD | 9 ++- src/main/python/apache/aurora/client/cli/BUILD | 25 +++++-- .../python/apache/aurora/client/cli/__init__.py | 50 ++++++-------- .../python/apache/aurora/client/cli/bridge.py | 52 ++++++++++++++ .../python/apache/aurora/client/cli/client.py | 51 ++++++++++++++ src/test/python/apache/aurora/client/cli/BUILD | 12 +++- .../apache/aurora/client/cli/test_bridge.py | 73 ++++++++++++++++++++ .../aurora/client/cli/test_cancel_update.py | 2 +- .../apache/aurora/client/cli/test_create.py | 2 +- .../apache/aurora/client/cli/test_diff.py | 2 +- .../apache/aurora/client/cli/test_kill.py | 4 +- .../apache/aurora/client/cli/test_quota.py | 2 +- .../apache/aurora/client/cli/test_restart.py | 3 +- .../apache/aurora/client/cli/test_status.py | 2 +- .../apache/aurora/client/cli/test_update.py | 3 +- 15 files changed, 250 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/bin/BUILD ---------------------------------------------------------------------- diff --git a/src/main/python/apache/aurora/client/bin/BUILD b/src/main/python/apache/aurora/client/bin/BUILD index 19fd9d3..dbabfd0 100644 --- a/src/main/python/apache/aurora/client/bin/BUILD +++ b/src/main/python/apache/aurora/client/bin/BUILD @@ -16,9 +16,16 @@ python_binary( name = 'aurora_client', - source = 'aurora_client.py', entry_point = 'apache.aurora.client.bin.aurora_client:proxy_main', dependencies = [ + pants(':aurora_client_lib') + ] +) + +python_library( + name = 'aurora_client_lib', + sources = [ 'aurora_client.py' ], + dependencies = [ pants('3rdparty/python:twitter.common.app'), pants('3rdparty/python:twitter.common.log'), pants('src/main/python/apache/aurora/client/commands:all'), http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/BUILD ---------------------------------------------------------------------- diff --git a/src/main/python/apache/aurora/client/cli/BUILD b/src/main/python/apache/aurora/client/cli/BUILD index 63954d6..f5c9ae7 100644 --- a/src/main/python/apache/aurora/client/cli/BUILD +++ b/src/main/python/apache/aurora/client/cli/BUILD @@ -16,13 +16,30 @@ python_binary( name='client', - entry_point = 'apache.aurora.client.cli:main', - dependencies = [ pants(':cli') ], - ) + entry_point = 'apache.aurora.client.cli.client:proxy_main', + dependencies = [ + pants(':client_lib') + ], +) + +python_library( + name = 'bridge', + sources = ['bridge.py'] +) + +python_library( + name = 'client_lib', + sources = [ 'client.py' ], + dependencies = [ + pants(':cli'), + pants(':bridge'), + pants('src/main/python/apache/aurora/client/bin:aurora_client_lib') + ] +) python_library( name='cli', - sources = globs('*.py'), + sources = [ '__init__.py', 'jobs.py', 'quota.py', 'context.py', 'options.py' ], dependencies = [ pants('3rdparty/python:argparse'), pants('3rdparty/python:twitter.common.python'), http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/__init__.py ---------------------------------------------------------------------- diff --git a/src/main/python/apache/aurora/client/cli/__init__.py b/src/main/python/apache/aurora/client/cli/__init__.py index 14a6676..9eb5c52 100644 --- a/src/main/python/apache/aurora/client/cli/__init__.py +++ b/src/main/python/apache/aurora/client/cli/__init__.py @@ -112,11 +112,13 @@ class CommandLine(object): """The top-level object implementing a command-line application.""" def __init__(self): - self.nouns = {} + self.nouns = None self.parser = None def register_noun(self, noun): """Add a noun to the application""" + if self.nouns is None: + self.nouns = {} if not isinstance(noun, Noun): raise TypeError('register_noun requires a Noun argument') self.nouns[noun.name] = noun @@ -132,18 +134,34 @@ class CommandLine(object): def register_nouns(self): """This method should overridden by applications to register the collection of nouns that they can manipulate. + + Noun registration is done on-demand, when either get_nouns or execute is called. + This allows the command-line tool a small amount of self-customizability depending + on the environment in which it is being used. + + For example, if a cluster is being run via AWS, then you could provide an + AWS noun with a set of operations for querying AWS status, billing stats, + etc. You wouldn't want to clutter the help output with AWS commands for users + that weren't using AWS. So you could have the command-line check the cluster.json + file, and only register the AWS noun if there was an AWS cluster. + """ - pass + + @property + def registered_nouns(self): + if self.nouns is None: + self.register_nouns() + return self.nouns.keys() def execute(self, args): """Execute a command. :param args: the command-line arguments for the command. This only includes arguments that should be parsed by the application; it does not include sys.argv[0]. """ - self.register_nouns() + nouns = self.registered_nouns self.setup_options_parser() options = self.parser.parse_args(args) - if options.noun not in self.nouns: + if options.noun not in nouns: raise ValueError('Unknown command: %s' % options.noun) noun = self.nouns[options.noun] context = noun.create_context() @@ -210,27 +228,3 @@ class Verb(AuroraCommand): def execute(self, context): pass - -class AuroraCommandLine(CommandLine): - """ An example implementation of a command line application using this framework. - This should probably eventually get moved in to its own source file. - """ - - @classmethod - def get_description(cls): - return 'Aurora client command line' - - def register_nouns(self): - from .jobs import Job - self.register_noun(Job()) - from .quota import Quota - self.register_noun(Quota()) - - -def main(): - cmd = AuroraCommandLine() - cmd.execute(sys.argv[1:]) - - -if __name__ == '__main__': - main(sys.argv) http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/bridge.py ---------------------------------------------------------------------- diff --git a/src/main/python/apache/aurora/client/cli/bridge.py b/src/main/python/apache/aurora/client/cli/bridge.py new file mode 100644 index 0000000..27079da --- /dev/null +++ b/src/main/python/apache/aurora/client/cli/bridge.py @@ -0,0 +1,52 @@ +import sys + + +class CommandProcessor(object): + """A wrapper for anything which can receive a set of command-line parameters and execute + something using them. + + This is built assuming that the first command-line parameter is the name of + a command to be executed. For example, if this was being used to build a command-line + tool named "tool", then a typical invocation from the command-line would look like + "tool cmd arg1 arg2". "cmd" would be the name of the command to execute, and + "arg1" and "arg2" would be the parameters to that command. + """ + + def execute(self, args): + """Execute the command-line tool wrapped by this processor. + + :param args: a list of the parameters used to invoke the command. Typically, + this will be sys.argv. + """ + pass + + def get_commands(self): + """Get a list of the commands that this processor can handle.""" + pass + + +class Bridge(object): + """Given multiple command line programs, each represented by a "CommandProcessor" object, + refer command invocations to the command line that knows how to process them. + """ + + def __init__(self, command_processors, default=None): + """ + :param command_processors: a list of command-processors. + :param default: the default command processor. any command which is not + reported by "get_commands" as part of any of the registered processors + will be passed to the default. + """ + self.command_processors = command_processors + self.default = default + + def execute(self, args): + """Dispatch a command line to the appropriate CommandProcessor""" + for cl in self.command_processors: + if args[1] in cl.get_commands(): + return cl.execute(args) + if self.default is not None: + return self.default.execute(args) + else: + print('Unknown command: %s' % args[1]) + sys.exit(1) http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/main/python/apache/aurora/client/cli/client.py ---------------------------------------------------------------------- diff --git a/src/main/python/apache/aurora/client/cli/client.py b/src/main/python/apache/aurora/client/cli/client.py new file mode 100644 index 0000000..e416d38 --- /dev/null +++ b/src/main/python/apache/aurora/client/cli/client.py @@ -0,0 +1,51 @@ +import sys + +from apache.aurora.client.cli import CommandLine +from apache.aurora.client.cli.bridge import Bridge, CommandProcessor + + +class AuroraCommandLine(CommandLine): + """The CommandLine implementation for the Aurora client v2 command line.""" + + @classmethod + def get_description(cls): + return 'Aurora client command line' + + def register_nouns(self): + super(AuroraCommandLine, self).register_nouns() + from apache.aurora.client.cli.jobs import Job + self.register_noun(Job()) + from apache.aurora.client.cli.quota import Quota + self.register_noun(Quota()) + + +class AuroraClientV2CommandProcessor(CommandProcessor): + def __init__(self): + self.commandline = AuroraCommandLine() + + def get_commands(self): + return self.commandline.registered_nouns + + def execute(self, args): + return self.commandline.execute(args[1:]) + + +class AuroraClientV1CommandProcessor(CommandProcessor): + # TODO(mchucarroll): deprecate client v1. (AURORA-131) + def get_commands(self): + return ["cancel_update", "create", "diff", "get_quota", "inspect", "kill", "list_jobs", + "open", "restart", "run", "ssh", "start_cron", "status", "update", "version" ] + + def execute(self, args): + from apache.aurora.client.bin.aurora_client import proxy_main as clientone_proxy_main + return clientone_proxy_main() + + +def proxy_main(): + v2 = AuroraClientV2CommandProcessor() + v1 = AuroraClientV1CommandProcessor() + bridge = Bridge([v2, v1], default=v1) + bridge.execute(sys.argv) + +if __name__ == '__main__': + proxy_main() http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/BUILD ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/BUILD b/src/test/python/apache/aurora/client/cli/BUILD index 51cc380..c106b97 100644 --- a/src/test/python/apache/aurora/client/cli/BUILD +++ b/src/test/python/apache/aurora/client/cli/BUILD @@ -16,7 +16,7 @@ python_test_suite( name = 'all', - dependencies = [ pants(':job'), pants(':quota') ] + dependencies = [ pants(':bridge'), pants(':job'), pants(':quota') ] ) python_library( @@ -29,6 +29,14 @@ python_library( ) python_tests( + name = 'bridge', + sources = [ 'test_bridge.py' ], + dependencies = [ + pants('src/main/python/apache/aurora/client/cli:bridge'), + ] +) + +python_tests( name = 'job', sources = [ 'test_cancel_update.py', @@ -44,6 +52,7 @@ python_tests( pants('3rdparty/python:mock'), pants('3rdparty/python:twitter.common.contextutil'), pants('src/main/python/apache/aurora/client/cli'), + pants('src/main/python/apache/aurora/client/cli:client'), pants('src/test/python/apache/aurora/client/commands:util') ] ) @@ -56,6 +65,7 @@ python_tests( pants('3rdparty/python:mock'), pants('3rdparty/python:twitter.common.contextutil'), pants('src/main/python/apache/aurora/client/cli'), + pants('src/main/python/apache/aurora/client/cli:client'), pants('src/test/python/apache/aurora/client/commands:util') ] ) http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_bridge.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_bridge.py b/src/test/python/apache/aurora/client/cli/test_bridge.py new file mode 100644 index 0000000..d944981 --- /dev/null +++ b/src/test/python/apache/aurora/client/cli/test_bridge.py @@ -0,0 +1,73 @@ +import unittest + +from apache.aurora.client.cli.bridge import Bridge, CommandProcessor + + +class CommandOne(CommandProcessor): + def get_commands(self): + return ['one', 'two', 'three'] + + def execute(self, args): + return 1 + + +class CommandTwo(CommandProcessor): + def get_commands(self): + return ['three', 'four', 'five'] + + def execute(self, args): + return 2 + + +class CommandThree(CommandProcessor): + def get_commands(self): + return ['six'] + + def execute(self, args): + return '3[%s]' % args[1] + + +class TestBridgedCommandLine(unittest.TestCase): + def setUp(self): + self.one = CommandOne() + self.two = CommandTwo() + self.three = CommandThree() + + def test_bridge_with_default_three(self): + bridge = Bridge([self.one, self.two, self.three], default=self.three) + assert bridge.execute(['test', 'one']) == 1 + assert bridge.execute(['test', 'two']) == 1 + assert bridge.execute(['test', 'three']) == 1 + assert bridge.execute(['test', 'four']) == 2 + assert bridge.execute(['test', 'five']) == 2 + assert bridge.execute(['test', 'six']) == '3[six]' + assert bridge.execute(['test', 'seven']) == '3[seven]' + assert bridge.execute(['test', 'eight']) == '3[eight]' + + def test_bridge_with_default_one(self): + bridge = Bridge([self.one, self.two, self.three], default=self.one) + assert bridge.execute(['test', 'one']) == 1 + assert bridge.execute(['test', 'two']) == 1 + assert bridge.execute(['test', 'three']) == 1 + assert bridge.execute(['test', 'four']) == 2 + assert bridge.execute(['test', 'five']) == 2 + assert bridge.execute(['test', 'six']) == '3[six]' + assert bridge.execute(['test', 'seven']) == 1 + assert bridge.execute(['test', 'eight']) == 1 + + def test_bridge_with_no_default(self): + bridge = Bridge([self.one, self.two, self.three]) + assert bridge.execute(['test', 'one']) == 1 + assert bridge.execute(['test', 'two']) == 1 + assert bridge.execute(['test', 'three']) == 1 + assert bridge.execute(['test', 'four']) == 2 + assert bridge.execute(['test', 'five']) == 2 + assert bridge.execute(['test', 'six']) == '3[six]' + self.assertRaises(SystemExit, bridge.execute, ['test', 'seven']) + + def test_bridge_ordering(self): + bridge1 = Bridge([self.one, self.two, self.three]) + bridge2 = Bridge([self.two, self.one, self.three]) + assert bridge1.execute(['test', 'three']) == 1 + assert bridge2.execute(['test', 'three']) == 2 + http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_cancel_update.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_cancel_update.py b/src/test/python/apache/aurora/client/cli/test_cancel_update.py index 92de1b9..e5cd7e5 100644 --- a/src/test/python/apache/aurora/client/cli/test_cancel_update.py +++ b/src/test/python/apache/aurora/client/cli/test_cancel_update.py @@ -16,7 +16,7 @@ import contextlib -from apache.aurora.client.cli import AuroraCommandLine +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext from apache.aurora.common.aurora_job_key import AuroraJobKey from twitter.common.contextutil import temporary_file http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_create.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_create.py b/src/test/python/apache/aurora/client/cli/test_create.py index 330bde5..4fff616 100644 --- a/src/test/python/apache/aurora/client/cli/test_create.py +++ b/src/test/python/apache/aurora/client/cli/test_create.py @@ -29,10 +29,10 @@ from gen.apache.aurora.ttypes import ( ) from apache.aurora.client.cli import ( - AuroraCommandLine, EXIT_COMMAND_FAILURE, EXIT_INVALID_CONFIGURATION ) +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext from apache.aurora.client.hooks.hooked_api import HookedAuroraClientAPI from apache.aurora.config import AuroraConfig http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_diff.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_diff.py b/src/test/python/apache/aurora/client/cli/test_diff.py index 32433c1..9c23a60 100644 --- a/src/test/python/apache/aurora/client/cli/test_diff.py +++ b/src/test/python/apache/aurora/client/cli/test_diff.py @@ -17,10 +17,10 @@ import contextlib from apache.aurora.client.cli import ( - AuroraCommandLine, EXIT_INVALID_CONFIGURATION, EXIT_INVALID_PARAMETER ) +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.cli.util import AuroraClientCommandTest from gen.apache.aurora.constants import ACTIVE_STATES http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_kill.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_kill.py b/src/test/python/apache/aurora/client/cli/test_kill.py index 9c593b9..6040ed4 100644 --- a/src/test/python/apache/aurora/client/cli/test_kill.py +++ b/src/test/python/apache/aurora/client/cli/test_kill.py @@ -17,7 +17,9 @@ import contextlib import unittest -from apache.aurora.client.cli import AuroraCommandLine +from twitter.common.contextutil import temporary_file + +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.hooks.hooked_api import HookedAuroraClientAPI from apache.aurora.common.aurora_job_key import AuroraJobKey from twitter.common.contextutil import temporary_file http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_quota.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_quota.py b/src/test/python/apache/aurora/client/cli/test_quota.py index d582fce..f7d3585 100644 --- a/src/test/python/apache/aurora/client/cli/test_quota.py +++ b/src/test/python/apache/aurora/client/cli/test_quota.py @@ -16,7 +16,7 @@ import contextlib -from apache.aurora.client.cli import AuroraCommandLine +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext from gen.apache.aurora.ttypes import ( http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_restart.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_restart.py b/src/test/python/apache/aurora/client/cli/test_restart.py index 3c04433..aa23d5b 100644 --- a/src/test/python/apache/aurora/client/cli/test_restart.py +++ b/src/test/python/apache/aurora/client/cli/test_restart.py @@ -2,7 +2,8 @@ import contextlib import functools from apache.aurora.client.api.health_check import InstanceWatcherHealthCheck, Retriable -from apache.aurora.client.cli import AuroraCommandLine, EXIT_API_ERROR +from apache.aurora.client.cli import EXIT_API_ERROR +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.cli.util import AuroraClientCommandTest from twitter.common.contextutil import temporary_file http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_status.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_status.py b/src/test/python/apache/aurora/client/cli/test_status.py index 38e14b1..c543f3d 100644 --- a/src/test/python/apache/aurora/client/cli/test_status.py +++ b/src/test/python/apache/aurora/client/cli/test_status.py @@ -29,9 +29,9 @@ from gen.apache.aurora.ttypes import ( ) from apache.aurora.client.cli import ( - AuroraCommandLine, EXIT_INVALID_PARAMETER ) +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.common.aurora_job_key import AuroraJobKey from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/e6f41508/src/test/python/apache/aurora/client/cli/test_update.py ---------------------------------------------------------------------- diff --git a/src/test/python/apache/aurora/client/cli/test_update.py b/src/test/python/apache/aurora/client/cli/test_update.py index c469da4..51858b9 100644 --- a/src/test/python/apache/aurora/client/cli/test_update.py +++ b/src/test/python/apache/aurora/client/cli/test_update.py @@ -6,7 +6,8 @@ from twitter.common.contextutil import temporary_file from apache.aurora.client.api.updater import Updater from apache.aurora.client.api.health_check import InstanceWatcherHealthCheck, Retriable from apache.aurora.client.api.quota_check import QuotaCheck -from apache.aurora.client.cli import AuroraCommandLine, EXIT_INVALID_CONFIGURATION +from apache.aurora.client.cli import EXIT_INVALID_CONFIGURATION +from apache.aurora.client.cli.client import AuroraCommandLine from apache.aurora.client.cli.util import AuroraClientCommandTest, FakeAuroraCommandContext from apache.aurora.config import AuroraConfig