diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 2fd803d..18a8709 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.32.0 +current_version = 1.32.1 commit = true tag = false diff --git a/configmanager/__init__.py b/configmanager/__init__.py index 2feafe2..5bc23f7 100644 --- a/configmanager/__init__.py +++ b/configmanager/__init__.py @@ -1,4 +1,4 @@ -__version__ = '1.32.0' +__version__ = '1.32.1' from .managers import Config from .items import Item diff --git a/configmanager/items.py b/configmanager/items.py index 8e04d9f..cf6c314 100644 --- a/configmanager/items.py +++ b/configmanager/items.py @@ -175,6 +175,27 @@ def default(self, value): return self._default = self.type.deserialize(value) + def _get_envvar_value(self): + """ + Internal helper to get item value from an environment variable + if item is controlled by one, and if the variable is set. + + Returns not_set otherwise. + """ + envvar_name = None + + if self.envvar is True: + envvar_name = self.envvar_name + if envvar_name is None: + envvar_name = '_'.join(self.get_path()).upper() + elif self.envvar: + envvar_name = self.envvar + + if envvar_name and envvar_name in os.environ: + return self.type.deserialize(os.environ[envvar_name]) + else: + return not_set + def get(self, fallback=not_set): """ Returns config value. @@ -182,16 +203,10 @@ def get(self, fallback=not_set): See Also: :meth:`.set` and :attr:`.value` """ - if self.envvar: - if self.envvar is True: - envvar_name = self.envvar_name - if envvar_name is None: - envvar_name = '_'.join(self.get_path()).upper() - if envvar_name in os.environ: - return self.type.deserialize(os.environ[envvar_name]) - else: - if self.envvar in os.environ: - return self.type.deserialize(os.environ[self.envvar]) + + envvar_value = self._get_envvar_value() + if envvar_value is not not_set: + return envvar_value if self.has_value: if self._value is not not_set: @@ -268,15 +283,26 @@ def reset(self): def is_default(self): """ ``True`` if the item's value is its default value or if no value and no default value are set. + + If the item is backed by an environment variable, this will be ``True`` only + if the environment variable is set and is different to the + default value of the item. """ - return self._value is not_set or self._value == self.default + envvar_value = self._get_envvar_value() + if envvar_value is not not_set: + return envvar_value == self.default + else: + return self._value is not_set or self._value == self.default @property def has_value(self): """ ``True`` if item has a default value or custom value set. """ - return self.default is not not_set or self._value is not not_set + if self._get_envvar_value() is not not_set: + return True + else: + return self.default is not not_set or self._value is not not_set @property def section(self): diff --git a/docs/index.rst b/docs/index.rst index 1377623..699db87 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -119,7 +119,7 @@ Similarly to reading, you find the appropriate persistence adapter, and use the config.json.dump('~/.config/helloworld/config.json', with_defaults=True) -Unless you also pass ``with_defaults=True``, ::dump:: will not include items who don't have a custom value set. +Unless you also pass ``with_defaults=True``, ``dump`` will exclude values for items who have no custom value set. How do I export all configuration values to a dictionary? --------------------------------------------------------- diff --git a/tests/test_item.py b/tests/test_item.py index e0a2151..48651eb 100644 --- a/tests/test_item.py +++ b/tests/test_item.py @@ -254,6 +254,17 @@ def test_is_default(): assert e.is_default +def test_is_default_respects_envvar(monkeypatch): + a = Item('a', default=5, envvar=True) + assert a.is_default + + monkeypatch.setenv('A', '5') + assert a.is_default + + monkeypatch.setenv('A', '6') + assert not a.is_default + + def test_has_value_returns_true_if_value_or_default_is_set(): c = Item() assert not c.has_value @@ -277,6 +288,14 @@ def test_has_value_returns_true_if_value_or_default_is_set(): assert not e.has_value +def test_has_value_respects_envvar(monkeypatch): + a = Item('a', envvar=True, type=int) + assert not a.has_value + + monkeypatch.setenv('A', '5') + assert a.has_value + + def test_type_is_guessed_either_from_default_or_value(): c = Item() assert c.type is Types.str