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_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_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_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_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 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_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_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)"])
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_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
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)
def setUp(self): """Set up the test fixture """ self.hod = HierarchicalOrderedDict()
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)