Skip to content

Commit

Permalink
Merge pull request #5 from xtopcla/master
Browse files Browse the repository at this point in the history
OPT: preserve order for override keys
  • Loading branch information
ricardosantosalves authored Aug 1, 2019
2 parents 68f40a9 + d48a9dd commit e441265
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
32 changes: 20 additions & 12 deletions settings_vial/settings_vial.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ class Settings:
42
"""

def __init__(self, env_prefix, override_prefix=None, override_keys_function=None):
def __init__(
self, env_prefix, override_prefix=None, override_keys_function=None, override_keys_reverse_lookup=False
):
self.env_prefix = env_prefix
self.override_prefix = override_prefix
self.override_keys_function = override_keys_function
self.override_keys_reverse_lookup = override_keys_reverse_lookup
self._config = {}
self._override_config = {}

Expand All @@ -37,15 +40,20 @@ def __repr__(self):

def __getattr__(self, attr):
if self.override_prefix and self.override_keys_function:
override_set = self._load_override_set()
override_keys = self._load_override_keys()

if override_set - set(self._override_config):
if set(override_keys) - set(self._override_config):
warnings.warn(
"There's no configuration with override keys {}".format(override_set - set(self._override_config)),
"There's no configuration with override keys {}".format(
set(override_keys) - set(self._override_config)
),
MissingOverrideKeysWarning,
)

for key in override_set:
if self.override_keys_reverse_lookup:
override_keys = reversed(override_keys)

for key in override_keys:
try:
return self._override_config[key][attr]
except KeyError:
Expand All @@ -56,18 +64,18 @@ def __getattr__(self, attr):
except KeyError:
raise AttributeError("{} has no attribute {}".format(self, attr))

def _load_override_set(self):
def _load_override_keys(self):
if not callable(self.override_keys_function):
warnings.warn("The callable provided is not a function", NotCallableWarning)
return set()
return tuple()

override_set = self.override_keys_function()
override_keys = self.override_keys_function()

if not isinstance(override_set, list) and not isinstance(override_set, set):
warnings.warn("Override callable does not return a set or a list", UnsupportedSetTypeWarning)
return set()
if not isinstance(override_keys, (list, tuple)):
warnings.warn("Override callable does not return a tuple or a list", UnsupportedSetTypeWarning)
return tuple()

return set(override_set)
return override_keys

def load_env(self):
r""" Loads configuration from environment variables as json encoded.
Expand Down
24 changes: 24 additions & 0 deletions tests/test_settings_vial.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ def mock_environment(monkeypatch):
env_dict = {
"USER": "test_environment",
"PREFIX_HASH": '{"dict": "test"}',
"PREFIX_VALUE_3": "default-value-3",
"PREFIX_DEBUG": "true",
"PREFIX_OVERRIDE_KEY_DEBUG": "false",
"PREFIX_SOME_KEY_PREFIX_REPEATED": "nested",
"PREFIX_OVERRIDE_KEY1_VALUE_1": "key1-value-1",
"PREFIX_OVERRIDE_KEY1_VALUE_2": "key1-value-2",
"PREFIX_OVERRIDE_KEY2_VALUE_1": "key2-value-1",
}

for var, value in env_dict.items():
Expand Down Expand Up @@ -100,6 +104,26 @@ def test_prefix_gets_stripped_once_only(self, mock_environment):

assert settings.SOME_KEY_PREFIX_REPEATED == "nested"

def test_override_keys_function_preserves_order_of_overrides(
self, mock_environment, override_keys_function, mocker
):
settings = Settings("PREFIX_", "OVERRIDE_", override_keys_function)
mocker.patch.object(settings, 'override_keys_function')
settings.override_keys_function.return_value = ("KEY1", "KEY2")
settings.load_env()
assert settings.VALUE_1 == "key1-value-1"
assert settings.VALUE_2 == "key1-value-2"
assert settings.VALUE_3 == "default-value-3"

def test_override_keys_reverse_lookup(self, mock_environment, override_keys_function, mocker):
settings = Settings("PREFIX_", "OVERRIDE_", override_keys_function, override_keys_reverse_lookup=True)
mocker.patch.object(settings, 'override_keys_function')
settings.override_keys_function.return_value = ("KEY1", "KEY2")
settings.load_env()
assert settings.VALUE_1 == "key2-value-1"
assert settings.VALUE_2 == "key1-value-2"
assert settings.VALUE_3 == "default-value-3"


class TestSettingsTypes:
@pytest.fixture
Expand Down

0 comments on commit e441265

Please sign in to comment.