From 7484e6c2fa3e12c76638c13f7e895e7b1e94a809 Mon Sep 17 00:00:00 2001 From: Brett Langdon Date: Wed, 25 Jul 2018 17:49:52 -0400 Subject: [PATCH] Load only predefined variables by default (#2) * Load only predefined variables by default * Have ENV_LOAD_ALL be True by default * Update docs * Add test asserting default behavior of ENV_LOAD_ALL --- README.rst | 9 +++++++++ flask_env.py | 6 ++++++ test_flask_env.py | 41 +++++++++++++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 14f92ed..e9a8cea 100644 --- a/README.rst +++ b/README.rst @@ -86,6 +86,14 @@ ENV_PREFIX The prefix will be removed from the environment variable name when setting in the configuration. (default: :code:`''`, example: :code:`ENV_PREFIX = 'MYAPP_'`) +ENV_LOAD_ALL + Whether or not to load all environment variables for the configuration object. + When :code:`False` only settings predefined on the configuration object are loaded, all others are ignored. + When :code:`True` all environment variables defined in :code:`os.environ` will get loaded into your configuration object. + (default :code:`True`) + + Note: Future versions will have default of :code:`False`. + Setting configuration values ---------------------------- @@ -99,3 +107,4 @@ You can set the :code:`flask-env` configuration settings directly on your Flask class Configuration(metaclass=MetaFlaskEnv): ENV_PREFIX = 'MYAPP_' + ENV_LOAD_ALL = False diff --git a/flask_env.py b/flask_env.py index dd4d554..52983a9 100644 --- a/flask_env.py +++ b/flask_env.py @@ -13,6 +13,7 @@ class MetaFlaskEnv(type): # Get our internal settings prefix = dict.get('ENV_PREFIX', '') + load_all = dict.get('ENV_LOAD_ALL', True) # Override default configuration from environment variables for key, value in os.environ.items(): @@ -23,6 +24,11 @@ class MetaFlaskEnv(type): # Strip the prefix from the environment variable name key = key[len(prefix):] + # Unless we specify that we want to load all environment variables + # only load variables that we have predefined on our object + if not load_all and not hasattr(cls, key): + continue + # If value is "true" or "false", parse as a boolean # Otherwise, if it contains a "." then try to parse as a float # Otherwise, try to parse as an integer diff --git a/test_flask_env.py b/test_flask_env.py index 562da3a..6d3a1c6 100644 --- a/test_flask_env.py +++ b/test_flask_env.py @@ -5,16 +5,29 @@ from flask_env import MetaFlaskEnv class TestFlaskEnv(unittest.TestCase): - def _get_test_configuration(self, env_prefix=''): + def _get_test_configuration(self, env_prefix='', env_load_all=False, **kwargs): """Helper to define a new configuration class using our MetaFlaskEnv""" return MetaFlaskEnv('TestConfiguration', (object, ), dict( ENV_PREFIX=env_prefix, - DEFAULT_SETTING='default_value', + ENV_LOAD_ALL=env_load_all, + **kwargs )) + def test_default_env_load_all(self): + """A test to ensure that we load all environment variables by default""" + # Configure an environment variable not defined on the configuration class + os.environ['TEST_SETTING'] = 'true' + + # Create our configuration object + TestConfiguration = MetaFlaskEnv('TestConfiguration', (object, ), dict()) + + # Assert that we loaded all environment variables + self.assertTrue(TestConfiguration.TEST_SETTING) + + def test_default_settings(self): """A test to ensure that if no environment variable is set, we get the default value that is set""" - TestConfiguration = self._get_test_configuration() + TestConfiguration = self._get_test_configuration(DEFAULT_SETTING='default_value') self.assertEqual(TestConfiguration.DEFAULT_SETTING, 'default_value') def test_override_from_env(self): @@ -22,7 +35,7 @@ class TestFlaskEnv(unittest.TestCase): # DEV: We have to set the environment variable first, since they get loaded into the class on definition os.environ['DEFAULT_SETTING'] = 'set_by_env' - TestConfiguration = self._get_test_configuration() + TestConfiguration = self._get_test_configuration(DEFAULT_SETTING='default_value') self.assertEqual(TestConfiguration.DEFAULT_SETTING, 'set_by_env') def test_only_set_on_env(self): @@ -30,15 +43,20 @@ class TestFlaskEnv(unittest.TestCase): # DEV: We have to set the environment variable first, since they get loaded into the class on definition os.environ['NEW_SETTING'] = 'set_by_env' - TestConfiguration = self._get_test_configuration() + # When configured to load all environment variables + TestConfiguration = self._get_test_configuration(env_load_all=True) self.assertEqual(TestConfiguration.NEW_SETTING, 'set_by_env') + # When configured to not load all environment variables + TestConfiguration = self._get_test_configuration(env_load_all=False) + self.assertFalse(hasattr(TestConfiguration, 'NEW_SETTING')) + def test_env_prefix(self): """A test to ensure that the ENV_PREFIX setting functions as needed""" # DEV: We have to set the environment variable first, since they get loaded into the class on definition os.environ['TEST_DEFAULT_SETTING'] = 'set_by_env' - TestConfiguration = self._get_test_configuration(env_prefix='TEST_') + TestConfiguration = self._get_test_configuration(env_prefix='TEST_', DEFAULT_SETTING='default_value') self.assertEqual(TestConfiguration.DEFAULT_SETTING, 'set_by_env') def test_env_prefix_non_matching(self): @@ -46,7 +64,7 @@ class TestFlaskEnv(unittest.TestCase): # DEV: We have to set the environment variable first, since they get loaded into the class on definition os.environ['DEFAULT_SETTING'] = 'set_by_env' - TestConfiguration = self._get_test_configuration(env_prefix='MYAPP_') + TestConfiguration = self._get_test_configuration(env_prefix='MYAPP_', DEFAULT_SETTING='default_value') self.assertEqual(TestConfiguration.DEFAULT_SETTING, 'default_value') def test_parsing_boolean(self): @@ -57,7 +75,8 @@ class TestFlaskEnv(unittest.TestCase): os.environ['IS_FALSE'] = 'FALSE' os.environ['IS_WACKY_FALSE'] = 'FaLSe' - TestConfiguration = self._get_test_configuration() + # DEV: Set `env_load_all=True` to keep from having to make default values for each variable + TestConfiguration = self._get_test_configuration(env_load_all=True) self.assertEqual(TestConfiguration.IS_TRUE, True) self.assertEqual(TestConfiguration.IS_NOT_TRUE, 'true-ish') self.assertEqual(TestConfiguration.IS_FALSE, False) @@ -71,7 +90,8 @@ class TestFlaskEnv(unittest.TestCase): os.environ['LEADING_DOT'] = '.12' os.environ['IS_NOT_FLOAT'] = 'This is 6.5' - TestConfiguration = self._get_test_configuration() + # DEV: Set `env_load_all=True` to keep from having to make default values for each variable + TestConfiguration = self._get_test_configuration(env_load_all=True) self.assertEqual(TestConfiguration.IS_FLOAT, 12.5) self.assertEqual(TestConfiguration.TRAILING_DOT, 12.0) self.assertEqual(TestConfiguration.LEADING_DOT, 0.12) @@ -84,7 +104,8 @@ class TestFlaskEnv(unittest.TestCase): os.environ['IS_ZERO'] = '0' os.environ['IS_NOT_INT'] = '12fa' - TestConfiguration = self._get_test_configuration() + # DEV: Set `env_load_all=True` to keep from having to make default values for each variable + TestConfiguration = self._get_test_configuration(env_load_all=True) self.assertEqual(TestConfiguration.IS_INT, 12) self.assertEqual(TestConfiguration.IS_ZERO, 0) self.assertEqual(TestConfiguration.IS_NOT_INT, '12fa')