diff --git a/src/freeseer/framework/config/profile.py b/src/freeseer/framework/config/profile.py index e6d8d386..5f417ee6 100644 --- a/src/freeseer/framework/config/profile.py +++ b/src/freeseer/framework/config/profile.py @@ -23,6 +23,7 @@ # http://wiki.github.com/Freeseer/freeseer/ import os +import shutil from freeseer.framework.config.persist import ConfigParserStorage from freeseer.framework.config.persist import JSONConfigStorage @@ -45,17 +46,79 @@ def _create_if_needed(self, path): # This is thrown if path already exists. pass - def get(self, name='default'): - """Retrieve Profile instances by name. + def get(self, name='default', create_if_needed=True): + """ + Retrieve Profile instances by name. Profiles are cached for future gets. + + Args: + name: The name of the profile. + create_if_needed: When True, get creates a new profile instance + if profile for given name doesn't exist. - Profiles are cached for future gets. + Returns: + The instance of Profile for the given name. + + Raises: + ProfileDoesNotExist: If create_if_needed==False and + the given profile name doesn't exist. """ - if name not in self._cache: + if name in self._cache: + return self._cache[name] + else: full_path = os.path.join(self._base_folder, name) - self._create_if_needed(full_path) - self._cache[name] = Profile(full_path, name) + if os.path.exists(full_path): + self._cache[name] = Profile(full_path, name) + return self._cache[name] + elif create_if_needed: + return self.create(name) + + raise ProfileDoesNotExist(name) + + def create(self, name): + """ + Creates a new Profile on file and adds it to the cache. + + Args: + name: The name of the profile to create. + + Returns: + The instance for the created Profile. + + Raises: + ProfileAlreadyExists: If a profile by the same name exists. + """ + path = os.path.join(self._base_folder, name) + try: + os.makedirs(path) + except OSError: + raise ProfileAlreadyExists(name) + + self._cache[name] = Profile(path, name) return self._cache[name] + def list_profiles(self): + """Returns a list of available profiles on file.""" + return os.listdir(self._base_folder) + + def delete(self, name): + """ + Deletes a profile and its configuration files from disk and cache. + + Args: + name: The name of the profile to delete. + + Raises: + ProfileDoesNotExist: If no profile exists for give name. + """ + path = os.path.join(self._base_folder, name) + try: + shutil.rmtree(path) + del self._cache[name] + except OSError: + raise ProfileDoesNotExist(name) + except KeyError: + pass + class Profile(object): """Represents a profile's config files, databases, and other stuff.""" @@ -129,3 +192,15 @@ def get_database(self, name='presentations.db'): if name not in self._databases: self._databases[name] = QtDBConnector(self.get_filepath(name), PluginManager(self)) return self._databases[name] + + +class ProfileAlreadyExists(Exception): + def __init__(self, value): + message = 'Profile already exists: "{}"'.format(value) + super(Exception, self).__init__(message) + + +class ProfileDoesNotExist(Exception): + def __init__(self, value): + message = 'Profile does not exist: "{}"'.format(value) + super(Exception, self).__init__(message) diff --git a/src/freeseer/tests/framework/config/test_profile.py b/src/freeseer/tests/framework/config/test_profile.py index b2ab17da..567c0752 100644 --- a/src/freeseer/tests/framework/config/test_profile.py +++ b/src/freeseer/tests/framework/config/test_profile.py @@ -26,13 +26,10 @@ import tempfile import unittest -from freeseer.framework.config import Config -from freeseer.framework.config import options +from freeseer.framework.config import Config, options from freeseer.framework.config.exceptions import StorageNotSetError -from freeseer.framework.config.persist import ConfigParserStorage -from freeseer.framework.config.persist import JSONConfigStorage -from freeseer.framework.config.profile import Profile -from freeseer.framework.config.profile import ProfileManager +from freeseer.framework.config.persist import ConfigParserStorage, JSONConfigStorage +from freeseer.framework.config.profile import Profile, ProfileAlreadyExists, ProfileDoesNotExist, ProfileManager from freeseer.framework.database import QtDBConnector @@ -56,12 +53,55 @@ def test_get(self): profile = self.profile_manager.get('testing') self.assertIsInstance(profile, Profile) + def test_get_non_existent(self): + """Test for non-existent profile.""" + self.assertRaises(ProfileDoesNotExist, self.profile_manager.get, 'non-existent_profile', create_if_needed=False) + + def test_get_non_existent_creates(self): + """Test that get creates non-existent profile if create_if_needed=True.""" + self.assertRaises(ProfileDoesNotExist, self.profile_manager.get, 'non-existent_profile', create_if_needed=False) + profile = self.profile_manager.get('non_existent_profile') + self.assertIsInstance(profile, Profile) + def test_get_cache(self): """Tests that get caching is working as expected.""" profile1 = self.profile_manager.get('testing') profile2 = self.profile_manager.get('testing') self.assertEqual(profile1, profile2) + def test_list_profiles(self): + """Tests that list_profiles returns all profiles on file.""" + self.profile_manager.create('testing1') + self.profile_manager.create('testing2') + profiles = self.profile_manager.list_profiles() + self.assertItemsEqual(['testing1', 'testing2'], profiles) + + def test_create_profile(self): + """Tests that create_profile returns an instance of Profile..""" + profile = self.profile_manager.create('testing1') + self.assertIsInstance(profile, Profile) + + def test_create_profile_existing(self): + """Tests that exception is raised if trying to overwrite existing profile.""" + self.profile_manager.create('testing1') + self.assertRaises(ProfileAlreadyExists, self.profile_manager.create, 'testing1') + + def test_create_profile_caches(self): + """Tests that create_profile adds the new Profile instance to cache.""" + self.assertNotIn('testing1', self.profile_manager._cache) + self.profile_manager.create('testing1') + self.assertIn('testing1', self.profile_manager._cache) + + def test_delete_profile_existing(self): + """Tests that delete_profile deletes the profile from cache and file.""" + self.profile_manager.create('testing1') + self.profile_manager.delete('testing1') + self.assertRaises(ProfileDoesNotExist, self.profile_manager.get, 'testing1', create_if_needed=False) + + def test_delete_profile_non_existing(self): + """Non-existent profiles can't be deleted.""" + self.assertRaises(ProfileDoesNotExist, self.profile_manager.delete, 'testing') + class TestProfile(unittest.TestCase): """Tests Profile."""