def __set__(self, obj, value): value = remove_convertible(value) self._check_type(value) if not isinstance(value, ScopedDict): value = ScopedDict(value) if value is not None else value Field.__set__(self, obj, value)
def test_scoped_dict_field(): class FieldTester: field = fields.ScopedDictField(int) field_maybe_none = fields.ScopedDictField( int, type(None)) tester = FieldTester() # Test valid assignments tester.field = { 'a': {'k1': 1, 'k2': 2}, 'a:b': {'k1': 3, 'k3': 4}, 'a:b:c': {'k2': 5, 'k3': 6}, '*': {'k1': 7, 'k3': 9, 'k4': 10} } tester.field_maybe_none = None # Check that we have indeed a ScopedDict here assert isinstance(FieldTester.field, fields.ScopedDictField) assert isinstance(tester.field, ScopedDict) assert 10 == tester.field['a:k4'] # Test invalid assignments with pytest.raises(TypeError): tester.field = {1: "a", 2: "b"} with pytest.raises(TypeError): tester.field = [('a', 1), ('b', 2)] with pytest.raises(TypeError): tester.field = {'a': {1: 'k1'}, 'b': {2: 'k2'}} # Test assigning a ScopedDict already tester.field = ScopedDict({})
def test_scoped_dict_field(self): class FieldTester: field = fields.ScopedDictField('field', int) field_maybe_none = fields.ScopedDictField('field_maybe_none', int, type(None)) tester = FieldTester() # Test valid assignments tester.field = { 'a': { 'k1': 1, 'k2': 2 }, 'a:b': { 'k1': 3, 'k3': 4 }, 'a:b:c': { 'k2': 5, 'k3': 6 }, '*': { 'k1': 7, 'k3': 9, 'k4': 10 } } tester.field_maybe_none = None # Check that we have indeed a ScopedDict here self.assertIsInstance(FieldTester.field, fields.ScopedDictField) self.assertIsInstance(tester.field, ScopedDict) self.assertEqual(10, tester.field['a:k4']) # Test invalid assignments self.assertRaises(TypeError, exec, 'tester.field = {1: "a", 2: "b" }', globals(), locals()) self.assertRaises(TypeError, exec, "tester.field = [('a', 1), ('b', 2)]", globals(), locals()) self.assertRaises( TypeError, exec, """tester.field = {'a': {1: 'k1'}, 'b': {2: 'k2'}}""", globals(), locals()) # Test assigning a ScopedDict already tester.field = ScopedDict({})
def select_subconfig(self, system_fullname=None, ignore_resolve_errors=False): if (self._local_system is not None and self._local_system == system_fullname): return system_fullname = system_fullname or self._detect_system() getlogger().debug(f'Selecting subconfig for {system_fullname!r}') try: system_name, part_name = system_fullname.split(':', maxsplit=1) except ValueError: # system_name does not have a partition system_name, part_name = system_fullname, None # Start from a fresh copy of the site_config, because we will be # modifying it site_config = copy.deepcopy(self._site_config) self._local_config = {} systems = list( filter(lambda x: x['name'] == system_name, site_config['systems'])) if not systems: raise ConfigError(f"could not find a configuration entry " f"for the requested system: '{system_name}'") if part_name is not None: # Filter out also partitions systems[0]['partitions'] = list( filter(lambda x: x['name'] == part_name, systems[0]['partitions'])) if not systems[0]['partitions']: raise ConfigError( f"could not find a configuration entry " f"for the requested system/partition combination: " f"'{system_name}:{part_name}'") # Create local configuration for the current or the requested system self._local_config['systems'] = systems for name, section in site_config.items(): if name == 'systems': # The systems sections has already been treated continue # Convert section to a scoped dict that will handle correctly and # transparently the system/partition resolution scoped_section = ScopedDict() for obj in section: key = obj.get('name', name) target_systems = obj.get( 'target_systems', _match_option(f'{name}/target_systems', self._schema['defaults'])) for t in target_systems: scoped_section[f'{t}:{key}'] = obj unique_keys = set() for obj in section: key = obj.get('name', name) if key in unique_keys: continue unique_keys.add(key) try: val = scoped_section[f"{system_fullname}:{key}"] except KeyError: pass else: self._local_config.setdefault(name, []) self._local_config[name].append(val) required_sections = self._schema['required'] for name in required_sections: if name not in self._local_config.keys(): if not ignore_resolve_errors: raise ConfigError(f"section '{name}' not defined " f"for system '{system_fullname}'") # Verify that all environments defined by the system are defined for # the current system if not ignore_resolve_errors: sys_environs = { *itertools.chain(*(p['environs'] for p in systems[0]['partitions'])) } found_environs = { e['name'] for e in self._local_config['environments'] } undefined_environs = sys_environs - found_environs if undefined_environs: env_descr = ', '.join(f"'{e}'" for e in undefined_environs) raise ConfigError(f"environments {env_descr} " f"are not defined for '{system_fullname}'") self._local_system = system_fullname