diff --git a/configerus/contrib/get/format.py b/configerus/contrib/get/format.py index ee27172..d7ba136 100644 --- a/configerus/contrib/get/format.py +++ b/configerus/contrib/get/format.py @@ -53,4 +53,4 @@ def format(self, key, default_label: str): label = default_label loaded = self.config.load(label) - return loaded.get(key, exception_if_missing=True) + return loaded.get(key) diff --git a/configerus/contrib/jsonschema/validate.py b/configerus/contrib/jsonschema/validate.py index f717037..7bea1e5 100644 --- a/configerus/contrib/jsonschema/validate.py +++ b/configerus/contrib/jsonschema/validate.py @@ -50,9 +50,13 @@ def validate(self, validate_target: Any, data): # returns of any value signal validation as validate only catches exceptions return + # This case means that we were told to look for a jsonschema source + # in config, which we can find by loading jsonschema as a config label + # and then treating the passed string as a config key for .get() + try: schema_config = self.config.load(PLUGIN_ID_VALIDATE_JSONSCHEMA_SCHEMA_CONFIG_LABEL) - schema = schema_config.get(validate_key, exception_if_missing=True) + schema = schema_config.get(validate_key) except Exception as e: raise NotImplementedError( diff --git a/configerus/format.py b/configerus/format.py index 81d0193..6954d05 100644 --- a/configerus/format.py +++ b/configerus/format.py @@ -147,6 +147,10 @@ def recursive_format(self, data: Any, default_label: str): def format_string(self, subject: str, default_label: str): """ format subject string, looking for and processing any formatting tags in the subject """ + # fast stop test. if no start tags are in the string then just abort + if self.START_MATCH not in subject: + return subject + subject_tokenized = subject for token in [ self.START_MATCH, diff --git a/configerus/loaded.py b/configerus/loaded.py index 6ee82b4..03e76af 100644 --- a/configerus/loaded.py +++ b/configerus/loaded.py @@ -53,8 +53,7 @@ def _reload(self, data): """ self.data = data - def has(self, key: Any = LOADED_KEY_ROOT, format: bool = True, - exception_if_missing: bool = False, validator: str = ""): + def has(self, key: Any = LOADED_KEY_ROOT): """ check if a key value exists in the config using a key, traverse a tree of data and return a boolean for if the key @@ -100,13 +99,16 @@ def has(self, key: Any = LOADED_KEY_ROOT, format: bool = True, Returns: -------- - Boolean : if a value exists in laoded config + Boolean : if a value exists in loaded config """ - return self.get(key, format=False, validator='', exception_if_missing=False) is not None + try: + tree_get(self.data, key, ignore=['', LOADED_KEY_ROOT]) + return True + except KeyError as e: + return False - def get(self, key: Any = LOADED_KEY_ROOT, format: bool = True, - exception_if_missing: bool = False, validator: str = ""): + def get(self, key: Any = LOADED_KEY_ROOT, format: bool = True, validator: str = "", default: Any = None): """ get a key value from the loaded config using a key, traverse a tree of data and return the value, optionally @@ -161,6 +163,9 @@ def get(self, key: Any = LOADED_KEY_ROOT, format: bool = True, Validation IS APPLIED if the key could not be matched. + default (Any) : default which will be returned if no matching key is + found. This means that no Exception will be thrown on KeyError + Returns: (Any) anything in the Dict is a valid return. The return could be a @@ -171,7 +176,8 @@ def get(self, key: Any = LOADED_KEY_ROOT, format: bool = True, Throws: Can throw a KeyError if the key cannot be found (which also occurs if - all sources produced no data and a non-empty key was passed.) + all sources produced no data and a non-empty key was passed,) ONLY IF + no default value was provided. """ value = "" @@ -180,12 +186,13 @@ def get(self, key: Any = LOADED_KEY_ROOT, format: bool = True, value = tree_get(self.data, key, ignore=['', LOADED_KEY_ROOT]) except KeyError as e: - if exception_if_missing: + if default is None: # hand off the exception raise e else: + # Use the default value logger.debug("Failed to find config key : %s", key) - value = None + value = default if format and value is not None: # try to format any values diff --git a/configerus/test/test_2_config_get_behaviour.py b/configerus/test/test_2_config_get_behaviour.py index c7bc19b..c0e6e70 100644 --- a/configerus/test/test_2_config_get_behaviour.py +++ b/configerus/test/test_2_config_get_behaviour.py @@ -189,9 +189,11 @@ def test_overrides(self): """ confirm that keys defined in more than one source get overriden """ self.assertEqual(self.loaded_config.get('4'), "fourth 4") - self.assertIsNone(self.loaded_config.get('5.1', exception_if_missing=False)) self.assertEqual(self.loaded_config.get('5'), "seventh 5 json") + with self.assertRaises(Exception): + self.loaded_config.get('5.1') + def test_get_multiple_keys(self): """ test the the loaded get of various key formats """ diff --git a/configerus/test/test_3_config_copy.py b/configerus/test/test_3_config_copy.py index d5439c2..e6c28d7 100644 --- a/configerus/test/test_3_config_copy.py +++ b/configerus/test/test_3_config_copy.py @@ -62,10 +62,14 @@ def test_copy_safety(self): # check original values self.assertEqual(config_copy_orig.get('one'), 'orig 1') - self.assertIsNone(config_copy_orig.get('two')) + with self.assertRaises(KeyError): + config_copy_orig.get('two') # check that copied config didn't modify original self.assertEqual(config_copy_orig.get('one'), config_copy_late.get('one')) - self.assertEqual(config_copy_orig.get('two'), config_copy_late.get('two')) + with self.assertRaises(KeyError): + config_copy_late.get('two') self.assertEqual(config1_copy.get('one'), 'copy1 1') self.assertEqual(config1_copy.get('two'), 'copy1 2') + self.assertEqual(config2_copy.get('one'), 'copy2 1') + self.assertEqual(config2_copy.get('two'), 'copy2 2') diff --git a/setup.cfg b/setup.cfg index 41a9826..fb6ca91 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = configerus -version = 2.0.0 +version = 3.0.0 description = Plugin-Based configuration manager long_description = file: README.md long_description_content_type = text/markdown