← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jtv/maas/maascli-profile-module into lp:maas

 

Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/maascli-profile-module into lp:maas.

Commit message:
Small maascli module for getting profiles.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jtv/maas/maascli-profile-module/+merge/128510

These will be needed for the main branch I'm working on.  I'm putting these up in smaller chunks so that a human can reasonably review them.

Once this work is complete, when you only have one profile defined in maascli, it will default to operating on that profile.  Specifying a profile will be optional in that case.  The helpers you see here help the code figure out which profile to use.  Several places in the code will need this information.  And with varying consequences, which is why there isn't much intelligence in this module: additional cleverness here might suit one use-case but complicate another.

You may wonder why the weirdness with islice() in name_default_profile.  It probably won't matter since the number of profiles will probably always be tiny, but this spelling retrieves exactly the necessary information without retrieving much more from the profile-config backing store: whether there are zero, one, or more profiles and if there is exactly one, its contents.


Jeroen
-- 
https://code.launchpad.net/~jtv/maas/maascli-profile-module/+merge/128510
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/maas/maascli-profile-module into lp:maas.
=== added file 'src/maascli/profile.py'
--- src/maascli/profile.py	1970-01-01 00:00:00 +0000
+++ src/maascli/profile.py	2012-10-08 14:49:22 +0000
@@ -0,0 +1,66 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Profile-related functionality."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = [
+    'get_profile',
+    'select_profile',
+    ]
+
+from itertools import islice
+
+
+class InvalidProfile(Exception):
+    """Unknown profile specified."""
+
+
+def get_profile(profiles, profile_name):
+    """Look up the named profile in `profiles`.
+
+    :param profiles: The result of `ProfileConfig.open()`.
+    :param profile_name: The profile requested by the user.
+    :return: The `ProfileConfig` option for the requested profile.
+    :raise InvalidProfile: Requested profile was not found.
+    """
+    if profile_name not in profiles:
+        raise InvalidProfile("'%s' is not an active profile." % profile_name)
+    return profiles[profile_name]
+
+
+def name_default_profile(profiles):
+    """Return name of the default profile, or raise `NoDefaultProfile`.
+
+    :param profiles: The result of `ProfileConfig.open()`.
+    :return: The name of the default profile, or None if there is no
+        reasonable default.
+    """
+    profiles_sample = list(islice(profiles, 2))
+    if len(profiles_sample) == 1:
+        # There's exactly one profile.  That makes a sensible default.
+        return profiles_sample[0]
+
+    return None
+
+
+def select_profile(profiles, profile_name=None):
+    """Return name for the applicable profile: the given name, or the default.
+
+    :param profiles: The result of `ProfileConfig.open()`.
+    :param profile_name: The profile requested by the user, if any.  This may
+        be `None`, in which case `select_profile` will look for a sensible
+        default to use.
+    :return: Name of the applicable profile, or `None` if no profile was
+        explicitly requested and no sensible default presents itself.
+    """
+    if profile_name is None:
+        return name_default_profile(profiles)
+    else:
+        return profile_name

=== added file 'src/maascli/tests/test_profile.py'
--- src/maascli/tests/test_profile.py	1970-01-01 00:00:00 +0000
+++ src/maascli/tests/test_profile.py	2012-10-08 14:49:22 +0000
@@ -0,0 +1,59 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for `maascli.profile`."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = []
+
+from maascli.profile import (
+    get_profile,
+    InvalidProfile,
+    name_default_profile,
+    select_profile,
+    )
+from maascli.testing.config import make_configs
+from maastesting.factory import factory
+from maastesting.testcase import TestCase
+
+
+class TestProfile(TestCase):
+
+    def test_get_profile_finds_profile(self):
+        profiles = make_configs()
+        [name] = profiles.keys()
+        self.assertEqual(profiles[name], get_profile(profiles, name))
+
+    def test_get_profile_raises_if_not_found(self):
+        profiles = make_configs()
+        self.assertRaises(
+            InvalidProfile,
+            get_profile, profiles, factory.make_name('nonexistent-profile'))
+
+    def test_name_default_profile_picks_single_profile(self):
+        profiles = make_configs(1)
+        [name] = profiles.keys()
+        self.assertEqual(name, name_default_profile(profiles))
+
+    def test_name_default_profile_returns_None_if_no_profile_found(self):
+        self.assertIsNone(name_default_profile(make_configs(0)))
+
+    def test_name_default_profile_returns_None_if_multiple_profiles(self):
+        profiles = make_configs(2)
+        self.assertIsNone(name_default_profile(profiles))
+
+    def test_select_profile_returns_named_profile(self):
+        profiles = make_configs(3)
+        profile_name = profiles.keys()[1]
+        self.assertEqual(profile_name, select_profile(profiles, profile_name))
+
+    def test_select_profile_selects_default_if_no_profile_named(self):
+        profiles = make_configs(1)
+        [name] = profiles.keys()
+        self.assertEqual(name, select_profile(profiles))