← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jtv/maas/maascli-split-cli-bis into lp:maas

 

Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/maascli-split-cli-bis into lp:maas.

Commit message:
Split maascli's CLI management commands off into their own module, away from the registration of API commands.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jtv/maas/maascli-split-cli-bis/+merge/128425

This was getting in the way of my attempts at a structural rearrangement to make maascli more user-friendly.  Next I'll introduce a new "cli" sub-command to encapsulate the CLI management commands, and make profile selection optional so that the API commands are directly in the maascli tool's main namespace.


Jeroen
-- 
https://code.launchpad.net/~jtv/maas/maascli-split-cli-bis/+merge/128425
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/maas/maascli-split-cli-bis into lp:maas.
=== modified file 'src/maascli/__init__.py'
--- src/maascli/__init__.py	2012-10-05 05:12:01 +0000
+++ src/maascli/__init__.py	2012-10-08 06:34:23 +0000
@@ -19,10 +19,8 @@
 import sys
 
 from bzrlib import osutils
-from maascli.api import (
-    register_api_commands,
-    register_cli_commands,
-    )
+from maascli.api import register_api_commands
+from maascli.cli import register_cli_commands
 from maascli.utils import parse_docstring
 
 

=== modified file 'src/maascli/api.py'
--- src/maascli/api.py	2012-10-08 05:24:57 +0000
+++ src/maascli/api.py	2012-10-08 06:34:23 +0000
@@ -12,7 +12,6 @@
 __metaclass__ = type
 __all__ = [
     "register_api_commands",
-    "register_cli_commands",
     ]
 
 from email.message import Message
@@ -25,19 +24,16 @@
     urlparse,
     )
 
-from apiclient.creds import convert_tuple_to_string
 from apiclient.maas_client import MAASOAuth
 from apiclient.multipart import encode_multipart_data
 from apiclient.utils import ascii_url
 import httplib2
-from maascli.auth import obtain_credentials
 from maascli.command import (
     Command,
     CommandError,
     )
 from maascli.config import ProfileConfig
 from maascli.utils import (
-    ensure_trailing_slash,
     handler_command_name,
     parse_docstring,
     safe_name,
@@ -105,97 +101,6 @@
         print(form % (cap(header), headers[header]), file=file)
 
 
-class cmd_login(Command):
-    """Log-in to a remote API, storing its description and credentials.
-
-    If credentials are not provided on the command-line, they will be prompted
-    for interactively.
-    """
-
-    def __init__(self, parser):
-        super(cmd_login, self).__init__(parser)
-        parser.add_argument(
-            "profile_name", metavar="profile-name", help=(
-                "The name with which you will later refer to this remote "
-                "server and credentials within this tool."
-                ))
-        parser.add_argument(
-            "url", help=(
-                "The URL of the remote API, e.g. "
-                "http://example.com/MAAS/api/1.0/";))
-        parser.add_argument(
-            "credentials", nargs="?", default=None, help=(
-                "The credentials, also known as the API key, for the "
-                "remote MAAS server. These can be found in the user "
-                "preferences page in the web UI; they take the form of "
-                "a long random-looking string composed of three parts, "
-                "separated by colons."
-                ))
-        parser.set_defaults(credentials=None)
-
-    def __call__(self, options):
-        # Try and obtain credentials interactively if they're not given, or
-        # read them from stdin if they're specified as "-".
-        credentials = obtain_credentials(options.credentials)
-        # Normalise the remote service's URL.
-        url = ensure_trailing_slash(options.url)
-        # Get description of remote API.
-        description = fetch_api_description(url)
-        # Save the config.
-        profile_name = options.profile_name
-        with ProfileConfig.open() as config:
-            config[profile_name] = {
-                "credentials": credentials,
-                "description": description,
-                "name": profile_name,
-                "url": url,
-                }
-
-
-class cmd_refresh(Command):
-    """Refresh the API descriptions of all profiles."""
-
-    def __call__(self, options):
-        with ProfileConfig.open() as config:
-            for profile_name in config:
-                profile = config[profile_name]
-                url = profile["url"]
-                profile["description"] = fetch_api_description(url)
-                config[profile_name] = profile
-
-
-class cmd_logout(Command):
-    """Log-out of a remote API, purging any stored credentials."""
-
-    def __init__(self, parser):
-        super(cmd_logout, self).__init__(parser)
-        parser.add_argument(
-            "profile_name", metavar="profile-name", help=(
-                "The name with which a remote server and its credentials "
-                "are referred to within this tool."
-                ))
-
-    def __call__(self, options):
-        with ProfileConfig.open() as config:
-            del config[options.profile_name]
-
-
-class cmd_list(Command):
-    """List remote APIs that have been logged-in to."""
-
-    def __call__(self, options):
-        with ProfileConfig.open() as config:
-            for profile_name in config:
-                profile = config[profile_name]
-                url = profile["url"]
-                creds = profile["credentials"]
-                if creds is None:
-                    print(profile_name, url)
-                else:
-                    creds = convert_tuple_to_string(creds)
-                    print(profile_name, url, creds)
-
-
 class Action(Command):
     """A generic MAAS API action.
 
@@ -348,23 +253,6 @@
         register_actions(profile, handler, handler_parser)
 
 
-commands = {
-    'login': cmd_login,
-    'logout': cmd_logout,
-    'list': cmd_list,
-    'refresh': cmd_refresh,
-}
-
-
-def register_cli_commands(parser):
-    """Register the CLI's meta-subcommands on `parser`."""
-    for name, command in commands.items():
-        help_title, help_body = parse_docstring(command)
-        command_parser = parser.subparsers.add_parser(
-            safe_name(name), help=help_title, description=help_body)
-        command_parser.set_defaults(execute=command(command_parser))
-
-
 def register_api_commands(parser):
     """Register all profiles as subcommands on `parser`."""
     with ProfileConfig.open() as config:

=== added file 'src/maascli/cli.py'
--- src/maascli/cli.py	1970-01-01 00:00:00 +0000
+++ src/maascli/cli.py	2012-10-08 06:34:23 +0000
@@ -0,0 +1,134 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""CLI management commands."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = [
+    'register_cli_commands',
+    ]
+
+from apiclient.creds import convert_tuple_to_string
+from maascli.api import fetch_api_description
+from maascli.auth import obtain_credentials
+from maascli.command import Command
+from maascli.config import ProfileConfig
+from maascli.utils import (
+    ensure_trailing_slash,
+    parse_docstring,
+    safe_name,
+    )
+
+
+class cmd_login(Command):
+    """Log-in to a remote API, storing its description and credentials.
+
+    If credentials are not provided on the command-line, they will be prompted
+    for interactively.
+    """
+
+    def __init__(self, parser):
+        super(cmd_login, self).__init__(parser)
+        parser.add_argument(
+            "profile_name", metavar="profile-name", help=(
+                "The name with which you will later refer to this remote "
+                "server and credentials within this tool."
+                ))
+        parser.add_argument(
+            "url", help=(
+                "The URL of the remote API, e.g. "
+                "http://example.com/MAAS/api/1.0/";))
+        parser.add_argument(
+            "credentials", nargs="?", default=None, help=(
+                "The credentials, also known as the API key, for the "
+                "remote MAAS server. These can be found in the user "
+                "preferences page in the web UI; they take the form of "
+                "a long random-looking string composed of three parts, "
+                "separated by colons."
+                ))
+        parser.set_defaults(credentials=None)
+
+    def __call__(self, options):
+        # Try and obtain credentials interactively if they're not given, or
+        # read them from stdin if they're specified as "-".
+        credentials = obtain_credentials(options.credentials)
+        # Normalise the remote service's URL.
+        url = ensure_trailing_slash(options.url)
+        # Get description of remote API.
+        description = fetch_api_description(url)
+        # Save the config.
+        profile_name = options.profile_name
+        with ProfileConfig.open() as config:
+            config[profile_name] = {
+                "credentials": credentials,
+                "description": description,
+                "name": profile_name,
+                "url": url,
+                }
+
+
+class cmd_refresh(Command):
+    """Refresh the API descriptions of all profiles."""
+
+    def __call__(self, options):
+        with ProfileConfig.open() as config:
+            for profile_name in config:
+                profile = config[profile_name]
+                url = profile["url"]
+                profile["description"] = fetch_api_description(url)
+                config[profile_name] = profile
+
+
+class cmd_logout(Command):
+    """Log-out of a remote API, purging any stored credentials."""
+
+    def __init__(self, parser):
+        super(cmd_logout, self).__init__(parser)
+        parser.add_argument(
+            "profile_name", metavar="profile-name", help=(
+                "The name with which a remote server and its credentials "
+                "are referred to within this tool."
+                ))
+
+    def __call__(self, options):
+        with ProfileConfig.open() as config:
+            del config[options.profile_name]
+
+
+class cmd_list(Command):
+    """List remote APIs that have been logged-in to."""
+
+    def __call__(self, options):
+        with ProfileConfig.open() as config:
+            for profile_name in config:
+                profile = config[profile_name]
+                url = profile["url"]
+                creds = profile["credentials"]
+                if creds is None:
+                    print(profile_name, url)
+                else:
+                    creds = convert_tuple_to_string(creds)
+                    print(profile_name, url, creds)
+
+
+commands = {
+    'login': cmd_login,
+    'logout': cmd_logout,
+    'list': cmd_list,
+    'refresh': cmd_refresh,
+}
+
+
+def register_cli_commands(parser):
+    """Register the CLI's meta-subcommands on `parser`."""
+    for name, command in commands.items():
+        help_title, help_body = parse_docstring(command)
+        command_parser = parser.subparsers.add_parser(
+            safe_name(name), help=help_title, description=help_body)
+        command_parser.set_defaults(execute=command(command_parser))

=== modified file 'src/maascli/tests/test_api.py'
--- src/maascli/tests/test_api.py	2012-10-08 05:24:57 +0000
+++ src/maascli/tests/test_api.py	2012-10-08 06:34:23 +0000
@@ -80,23 +80,6 @@
         self.assertIsNotNone(parser.subparsers.choices[profile])
 
 
-class TestRegisterCLICommands(TestCase):
-    """Tests for `register_cli_commands`."""
-
-    def test_registers_subparsers(self):
-        parser = ArgumentParser()
-        self.assertIsNone(parser._subparsers)
-        api.register_cli_commands(parser)
-        self.assertIsNotNone(parser._subparsers)
-
-    def test_subparsers_have_appropriate_execute_defaults(self):
-        parser = ArgumentParser()
-        api.register_cli_commands(parser)
-        self.assertIsInstance(
-            parser.subparsers.choices['login'].get_default('execute'),
-            api.cmd_login)
-
-
 class TestFunctions(TestCase):
     """Test for miscellaneous functions in `maascli.api`."""
 

=== added file 'src/maascli/tests/test_cli.py'
--- src/maascli/tests/test_cli.py	1970-01-01 00:00:00 +0000
+++ src/maascli/tests/test_cli.py	2012-10-08 06:34:23 +0000
@@ -0,0 +1,36 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for `maascli.cli`."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = []
+
+from maascli import (
+    ArgumentParser,
+    cli,
+    )
+from maastesting.testcase import TestCase
+
+
+class TestRegisterCLICommands(TestCase):
+    """Tests for `register_cli_commands`."""
+
+    def test_registers_subparsers(self):
+        parser = ArgumentParser()
+        self.assertIsNone(parser._subparsers)
+        cli.register_cli_commands(parser)
+        self.assertIsNotNone(parser._subparsers)
+
+    def test_subparsers_have_appropriate_execute_defaults(self):
+        parser = ArgumentParser()
+        cli.register_cli_commands(parser)
+        self.assertIsInstance(
+            parser.subparsers.choices['login'].get_default('execute'),
+            cli.cmd_login)


Follow ups