From 5da2c3255371a12a35c46f41e8c744053ad07887 Mon Sep 17 00:00:00 2001 From: Chris Haumesser <1550854+wryfi@users.noreply.github.com> Date: Mon, 12 Aug 2019 08:00:20 -0700 Subject: [PATCH] improve support for booleans in environment vars --- ChangeLog | 5 +++++ cfitall/config.py | 14 ++++++++++++-- cfitall/tests/test_config.py | 28 +++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5c0738a..26dcd78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ CHANGES ======= +v1.0.0 +------ + +* add license +* add AUTHORS and ChangeLog per pbr * update README * add json and yaml convenience methods * more work removing string > list conversions diff --git a/cfitall/config.py b/cfitall/config.py index 5580e67..0e08472 100644 --- a/cfitall/config.py +++ b/cfitall/config.py @@ -8,7 +8,7 @@ class ConfigManager(object): - def __init__(self, name, env_prefix=None, env_path_sep='__', env_value_split=True, defaults={}): + def __init__(self, name, env_prefix=None, env_path_sep='__', env_value_split=True, env_bool=True, defaults={}): """ The configuration registry holds configuration data from different sources and reconciles it for retrieval. @@ -16,7 +16,8 @@ def __init__(self, name, env_prefix=None, env_path_sep='__', env_value_split=Tru :param str name: name of registry (cannot contain env_separator string) :param str env_prefix: prefix for environment variables (defaults to uppercase name) :param str env_path_sep: string for separating config hierarchies in env vars (default '__') - :param bool env_value_split: if True, then environment variable values are split on commas into a list + :param bool env_value_split: split env var values into python string (on comma) + :param bool env_bool: convert 'true' and 'false' strings in env vars to python bools :param dict defaults: dictionary of default configuration settings """ self.name = name @@ -25,6 +26,7 @@ def __init__(self, name, env_prefix=None, env_path_sep='__', env_value_split=Tru self.values = {'super': {}, 'cli': {}, 'cfgfile': {}, 'defaults': defaults} self.env_path_sep = env_path_sep self.env_value_split = env_value_split + self.env_bool = env_bool if env_prefix: self.env_prefix = env_prefix.upper() else: @@ -212,6 +214,14 @@ def _read_environment(self): if isinstance(value, str) and self.env_value_split: if re.match(r'.*,(.*,)*.*', value): value = value.split(',') + if self.env_bool: + if type(value) == str and value.lower() == 'true': + value = True + if type(value) == str and value.lower() == 'false': + value = False + if type(value) == list: + value = [True if type(val) == str and val.lower() == 'true' else val for val in value] + value = [False if type(val) == str and val.lower() == 'false' else val for val in value] output[key] = value return utils.expand_flattened_dict(output, separator=self.env_path_sep) diff --git a/cfitall/tests/test_config.py b/cfitall/tests/test_config.py index 9bfd444..b084033 100644 --- a/cfitall/tests/test_config.py +++ b/cfitall/tests/test_config.py @@ -13,9 +13,9 @@ def setUp(self): def tearDown(self): super().tearDown() - del os.environ['CFITALL__GLOBAL__NAME'] - del os.environ['CFITALL__GLOBAL__PATH'] - del os.environ['CFITALL__FOO__BANG'] + for key, value in os.environ.items(): + if key.startswith('CFITALL'): + del os.environ[key] def test_create_object(self): _cf = ConfigManager('cfitall') @@ -49,6 +49,28 @@ def test_config_order(self): cf.set('global.authors', ['dwight schrute', 'pam beesly']) self.assertEqual(cf.get('global.authors', list), ['dwight schrute', 'pam beesly']) + def test_env_bool(self): + cf = ConfigManager('cfitall') + os.environ['CFITALL__TEST__BOOLEAN__TRUE'] = 'true' + os.environ['CFITALL__TEST__BOOLEAN__FALSE'] = 'False' + os.environ['CFITALL__TEST__BOOLEAN__LIST'] = 'true,false,True,this,False,is,nice' + self.assertEqual(cf.get('test.boolean.true'), True) + self.assertEqual(cf.get('test.boolean.false'), False) + self.assertEqual(cf.get('test.boolean.list'), [True, False, True, 'this', False, 'is', 'nice']) + cf.env_bool = False + self.assertEqual(cf.get('test.boolean.true'), 'true') + self.assertEqual(cf.get('test.boolean.false'), 'False') + self.assertEqual(cf.get('test.boolean.list'), ['true', 'false', 'True', 'this', 'False', 'is', 'nice']) + + def test_comma_list(self): + cf = ConfigManager('cfitall') + cf.set_default('test.list.withcommas', ['flenderson, toby', 'martin, angela']) + self.assertEqual(cf.get('test.list.withcommas'), ['flenderson, toby', 'martin, angela']) + os.environ['CFITALL__TEST__LIST'] = 'hello,world,melting' + self.assertEqual(cf.get('test.list'), ['hello', 'world', 'melting']) + cf.env_value_split = False + self.assertEqual(cf.get('test.list'), 'hello,world,melting') + if __name__ == '__main__': unittest.main()