def test_get_or_set(self): """Test get_or_setting values """ self.hod = HierarchicalOrderedDict() self.assertRaises(KeyError, self.hod.get, 'a') self.assertEqual(self.hod.get_or_set('a', 42), 42) self.assertEqual(self.hod.get('a'), 42) self.hod['a'] = 52 self.assertEqual(self.hod.get_or_set('a', 42), 52)
def test_merge_empty(self): """Test merging in empty mapping """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() self.hod.merge(m_2) self.assertEqual(len(self.hod), 4) for key, value in items: self.hod[key] = value
def test_boolean_spec(self): """Test generating a spec from a boolean """ default = HierarchicalOrderedDict() default['a'] = True self.assert_equal_encoded_list( ohm_to_spec(default), ["a = boolean(default=True)"])
def test_string_spec(self): """Test generating a spec from a string """ default = HierarchicalOrderedDict() default['a'] = "bla" self.assert_equal_encoded_list( ohm_to_spec(default), ["a = string(default=bla)"])
def test_float_spec(self): """Test generating a spec from a float """ default = HierarchicalOrderedDict() default['a'] = 1.2 self.assert_equal_encoded_list( ohm_to_spec(default), ["a = float(default=1.2)"])
def test_int_spec(self): """Test generating a spec from an integer """ default = HierarchicalOrderedDict() default['a'] = 12 self.assert_equal_encoded_list( ohm_to_spec(default), ["a = integer(default=12)"])
def test_level1_spec(self): """Test generating a spec with one level """ default = HierarchicalOrderedDict() default['a.b'] = 1.2 self.assert_equal_encoded_list( ohm_to_spec(default), ["[a]", "b = float(default=1.2)"])
def test_merge_same(self): """Test merging mapping with same keys """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() m_2['a'] = 12 m_2['b'] = 13 m_2['c.d'] = 14 m_2['e.f.g'] = 15 self.hod.merge(m_2) self.assertEqual(len(self.hod), 4) for key, value in items: self.hod[key] = value
def conf_to_ohm(conf, ohm=None, section_name=''): """Converts a configobj to an OrderedHierarchicalMapping """ if conf is None: return HierarchicalOrderedDict() if ohm is None: ohm = HierarchicalOrderedDict() for key, value in conf.items(): if not section_name == '': new_key = (section_name + HierarchicalOrderedDict.SECTION_SEPARATOR + key) else: new_key = key if not isinstance(value, configobj.Section): ohm[new_key] = value else: conf_to_ohm(value, ohm=ohm, section_name=new_key) return ohm
def test_merge_other_keys(self): """Test merging in mapping with other keys """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() m_2['k'] = 13 m_2['l.m.n'] = 'bla' items2 = list(m_2.items()) self.hod.merge(m_2) self.assertEqual(len(self.hod), 6) for key, value in items + items2: self.hod[key] = value
def test_base_keys(self): """Test getting the base keys """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 base_keys = self.hod.base_keys() self.assertIn('a', base_keys) self.assertIn('b', base_keys) self.assertIn('c', base_keys) self.assertIn('e', base_keys) self.assertNotIn('c.d', base_keys) self.assertNotIn('d', base_keys) self.assertNotIn('e.f', base_keys) self.assertNotIn('e.f.g', base_keys) self.assertNotIn('f.g', base_keys) self.assertNotIn('f', base_keys) self.assertNotIn('g', base_keys)
def test_level2_spec(self): """Test generating a spec with two levels """ default = HierarchicalOrderedDict() default['a.b'] = 1.2 default['a.c.d'] = 3 self.assert_equal_encoded_list( ohm_to_spec(default), ["[a]", "b = float(default=1.2)", "[[c]]", "d = integer(default=3)"])
def test_merge_overlapping(self): """Test merging in mapping with overlapping keys """ self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() m_2['c.d'] = 10 m_2['k'] = 13 m_2['l.m.n'] = 'bla' items2 = list(m_2.items()) self.hod.merge(m_2) self.assertEqual(len(self.hod), 6) for key, value in items: self.hod[key] = value for key, value in items2: if key not in [item[0] for item in items]: self.hod[key] = value
def test_level1_spec_unordered(self): """Test generating a spec with one level and wrong order """ default = HierarchicalOrderedDict() default['a.b'] = 1.2 default['c'] = 3.4 default['n.k'] = 2 default['d.a'] = 3 default['a.a'] = 1 self.assert_equal_encoded_list( ohm_to_spec(default), ["c = float(default=3.4)", "[a]", "a = integer(default=1)", "b = float(default=1.2)", "[d]", "a = integer(default=3)", "[n]", "k = integer(default=2)"])
class TestHierarchicalOrderedDict(unittest.TestCase): """Test the ``HierarchicalOrderedDict`` """ def setUp(self): """Set up the test fixture """ self.hod = HierarchicalOrderedDict() def test_len_empty_mapping(self): """Test if the empty mapping is really empty """ self.assertEqual(len(self.hod), 0) def test_insert_retrieve_base_level(self): """Make sure we can use the container at the base """ self.hod['a'] = 12 self.assertEqual(self.hod['a'], 12) def test_retrieve_second_level(self): """Make sure we can use the container at the second level """ self.hod['hello.world'] = 12 self.assertEqual(self.hod['hello.world'], 12) def test_len_after_first_level(self): """Test if the length is correct after inserting at the first level """ self.assertEqual(len(self.hod), 0) # New keys should increase the length for i, key in enumerate(['a', 'b', 'c', 'd', 'e', 'f']): self.hod[key] = i ** 2 self.assertEqual(len(self.hod), i + 1) # Existing keys should keep the length for key in ['a', 'b', 'c', 'd', 'e', 'f']: self.hod[key] = 12 self.assertEqual(len(self.hod), 5 + 1) def test_inserting_higher_levels(self): """Test if the length is correct after inserting at the first level """ self.assertEqual(len(self.hod), 0) # New keys should increase the length i = 0 for key1 in ['a', 'b', 'c', 'd', 'e', 'f']: for key2 in ['a', 'b', 'c', 'd', 'e', 'f']: i += 1 self.hod[key1 + '.' + key2] = i self.assertEqual(len(self.hod), i) def test_keys(self): """Test the keys method on the mapping """ self.assertEqual(len(self.hod), 0) # New keys keys = ['a', 'b', 'c', 'd', 'e', 'f'] for i, key in enumerate(keys): self.hod[key] = i self.assertEqual(list(self.hod.keys()), keys) def test_contains(self): """Test the HierarchicalOrderedDict with `in` """ self.assertEqual(len(self.hod), 0) self.assertFalse('a' in self.hod) self.hod['a'] = 1 self.assertTrue('a' in self.hod) self.assertFalse('b.c.d' in self.hod) self.hod['b.c.d'] = 1 self.assertTrue('b.c.d' in self.hod) def test_get(self): """Test getting values with and without default values """ self.assertRaises(KeyError, self.hod.get, 'a') self.assertEqual(self.hod.get('a', 42), 42) self.hod['a'] = 123 self.assertEqual(self.hod.get('a', 42), 123) def test_get_or_set(self): """Test get_or_setting values """ self.hod = HierarchicalOrderedDict() self.assertRaises(KeyError, self.hod.get, 'a') self.assertEqual(self.hod.get_or_set('a', 42), 42) self.assertEqual(self.hod.get('a'), 42) self.hod['a'] = 52 self.assertEqual(self.hod.get_or_set('a', 42), 52) def test_set_wrong_key(self): """Test error is raised when keys are not strings """ self.assertRaises(TypeError, self.hod.__setitem__, 12, 13) def test_base_keys(self): """Test getting the base keys """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 base_keys = self.hod.base_keys() self.assertIn('a', base_keys) self.assertIn('b', base_keys) self.assertIn('c', base_keys) self.assertIn('e', base_keys) self.assertNotIn('c.d', base_keys) self.assertNotIn('d', base_keys) self.assertNotIn('e.f', base_keys) self.assertNotIn('e.f.g', base_keys) self.assertNotIn('f.g', base_keys) self.assertNotIn('f', base_keys) self.assertNotIn('g', base_keys) def test_merge_empty(self): """Test merging in empty mapping """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() self.hod.merge(m_2) self.assertEqual(len(self.hod), 4) for key, value in items: self.hod[key] = value def test_merge_same(self): """Test merging mapping with same keys """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() m_2['a'] = 12 m_2['b'] = 13 m_2['c.d'] = 14 m_2['e.f.g'] = 15 self.hod.merge(m_2) self.assertEqual(len(self.hod), 4) for key, value in items: self.hod[key] = value def test_merge_other_keys(self): """Test merging in mapping with other keys """ self.hod = HierarchicalOrderedDict() self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() m_2['k'] = 13 m_2['l.m.n'] = 'bla' items2 = list(m_2.items()) self.hod.merge(m_2) self.assertEqual(len(self.hod), 6) for key, value in items + items2: self.hod[key] = value def test_merge_overlapping(self): """Test merging in mapping with overlapping keys """ self.hod['a'] = 12 self.hod['b'] = 13 self.hod['c.d'] = 14 self.hod['e.f.g'] = 15 items = list(self.hod.items()) m_2 = HierarchicalOrderedDict() m_2['c.d'] = 10 m_2['k'] = 13 m_2['l.m.n'] = 'bla' items2 = list(m_2.items()) self.hod.merge(m_2) self.assertEqual(len(self.hod), 6) for key, value in items: self.hod[key] = value for key, value in items2: if key not in [item[0] for item in items]: self.hod[key] = value def test_section_keys(self): """Test the section_keys method on the mapping """ self.assertEqual(len(list(self.hod.section_keys())), 0) # New keys keys = ['a', 'b.c', 'd.e.f', 'g.h', 'j.k.l.m'] for i, key in enumerate(keys): self.hod[key] = i self.assertIn('b', self.hod.section_keys()) self.assertIn('d.e', self.hod.section_keys()) self.assertIn('g', self.hod.section_keys()) self.assertIn('j.k.l', self.hod.section_keys()) self.assertNotIn('a', self.hod.section_keys()) self.assertNotIn('c', self.hod.section_keys()) self.assertNotIn('b.c', self.hod.section_keys()) self.assertNotIn('e', self.hod.section_keys()) self.assertNotIn('e.f', self.hod.section_keys()) self.assertNotIn('d.e.f', self.hod.section_keys()) self.assertNotIn('h', self.hod.section_keys()) self.assertNotIn('m', self.hod.section_keys())
def reset_instance(cls): """Overloads reset_instance to reset the DEFAULT_CONFIG """ cls.DEFAULT_CONFIG = HierarchicalOrderedDict() super(Config, cls).reset_instance()
def test_empty_ohm(self): """Test converting empty ohm """ ohm = HierarchicalOrderedDict() conf = ohm_to_spec(ohm) self.assertIsInstance(conf, list)
def setUp(self): """Set up the test fixture """ self.hod = HierarchicalOrderedDict()
class Config( HierarchicalMapping, # pylint: disable=too-many-ancestors DefaultSingleton): """Represents a singleton configuration object. """ CONFIG_SPEC_PATH = 'configspec.ini' """Path of the file with the specification for configurations. """ DEFAULT_CONFIG = HierarchicalOrderedDict() """Default configuration, later used by initialize """ @classmethod def _is_section(cls, obj): """Returns true if obj is a section """ return isinstance(obj, configobj.Section) @classmethod def reset_instance(cls): """Overloads reset_instance to reset the DEFAULT_CONFIG """ cls.DEFAULT_CONFIG = HierarchicalOrderedDict() super(Config, cls).reset_instance() @classmethod def _get_pseudo_instance(cls): """Overloaded method returning the DEFAULT_CONFIG with added methods """ def save_unitialized(filename): """Saves an unitialized config """ cls.initialize() cls.get_instance().save(filename) cls.DEFAULT_CONFIG.reset_instance = Config.reset_instance cls.DEFAULT_CONFIG.load = cls.initialize cls.DEFAULT_CONFIG.save = save_unitialized return cls.DEFAULT_CONFIG def _new_section(self, parent, level): """Creates a new section Mapping """ return configobj.Section(parent, level, self.base) def __init__(self, filename=None, spec=CONFIG_SPEC_PATH, options=None, default_spec=None): """Initializer """ super(Config, self).__init__() self.read_from_file = None self.filename = None # Merge specs, giving precedence to user spec, then, before_init_spec, # then default_spec if ((spec == self.CONFIG_SPEC_PATH and not os.path.isfile(self.CONFIG_SPEC_PATH))): spec = None user_spec_ohm = thread_first(spec, convert_spec, conf_to_ohm) before_init_spec_ohm = thread_first(self.DEFAULT_CONFIG, ohm_to_spec, convert_spec, conf_to_ohm) default_spec_ohm = thread_first(default_spec, convert_spec, conf_to_ohm) user_spec_ohm.merge(before_init_spec_ohm) user_spec_ohm.merge(default_spec_ohm) full_spec = ohm_to_spec_list(user_spec_ohm) # Load the configuration and overload it with the options if filename is not None: self.load(filename, full_spec, options) else: self.base = configobj.ConfigObj() # Unless the options are already there, overload them with the defaults # set before initialization for key, value in self.DEFAULT_CONFIG.items(): if key not in self: self[key] = value def override_with_args(self, options): """Override configuration with option dictionary """ for key, value in options: self[key] = value @staticmethod def validate_config(config): """Validate configuration """ validator = validate.Validator() result = config.validate(validator, copy=True, preserve_errors=True) if not isinstance(result, bool): raise ValueError("Configuration does not adhere" " to the specification: %s" % configobj.flatten_errors(config, result)) elif not result: # This should never happen raise RuntimeError( # pragma: no cover "Configuration validated to false.") def load(self, filename, spec=None, options=None): """Loads a configuration from filename (or string). Missing values will be read from the specification file or string. """ # Check if config file exists read_from_file = os.path.isfile(filename) if read_from_file: self.filename = filename # Create the configuration (overriding the default with user # specs if necessary) self.base = configobj.ConfigObj(filename, configspec=spec) # Override options if options is not None: self.override_with_args(options) # Validate the configuration if spec is not None: self.validate_config(self.base) # Add some more info self.base.read_from_file = read_from_file def save(self, filename): """Write configuration to file """ if self.base is None: # This should never happen raise RuntimeError( # pragma: no cover "Configuration not initialized yet.") else: with open(filename, 'wb') as outfile: self.base.write(outfile)