diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ddcbb1a..9b1c51f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,7 @@ v0.8 (unreleased) ==== Test with Python 3.9 and Python 3.10. +Fix interpolation of multiple variables in one setting value. v0.7 diff --git a/configstore/store.py b/configstore/store.py index 9e694b5..01d6ffe 100644 --- a/configstore/store.py +++ b/configstore/store.py @@ -73,7 +73,7 @@ def get_setting(self, key, default=_no_default, *, asbool=False): return ret def interpolate(self, string): - res = re.sub(r"\$\{([_a-zA-Z0-9]+)\}", self._replace, string, count=1) + res = re.sub(r"\$\{([_a-zA-Z0-9]+)\}", self._replace, string) return res def _replace(self, matchobj): diff --git a/tests/test_store.py b/tests/test_store.py index 31dae8a..d6c5f58 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -74,6 +74,13 @@ def test_store_get_setting_interpolate_value(): assert value == '42-staging-secrets!' +def test_store_get_setting_interpolate_missing(): + store = Store([DictBackend({'service_host': 'cool-db-server:6000'})]) + + with pytest.raises(SettingNotFoundException): + store.get_setting('service_url') + + def test_store_get_setting_interpolate_default(): store = Store([DictBackend({'service_host': 'cool-db-server:6000'})]) @@ -82,6 +89,21 @@ def test_store_get_setting_interpolate_default(): assert value == 'https://cool-db-server:6000/db' +def test_store_get_setting_interpolate_special_character_boundary(): + store = Store([DictBackend(dict( + service_url='https://${user}:${dbpass}@${host}:${port}/${db}', + user='bob', + dbpass='secret', + host='cool-db-server', + port='6000', + db='db1', + ))]) + + value = store.get_setting('service_url') + + assert value == 'https://bob:secret@cool-db-server:6000/db1' + + def test_store_add_backend(): store = Store([]) diff --git a/tests/test_z_integration.py b/tests/test_z_integration.py index a8cc170..93278bb 100644 --- a/tests/test_z_integration.py +++ b/tests/test_z_integration.py @@ -89,10 +89,15 @@ def test_dict_defaults(monkeypatch): def test_interpolation(monkeypatch, tmp_path): monkeypatch.setenv('ENVIRONMENT', 'STAGING') - monkeypatch.setenv('REDIS_URL', 'https://redis:4012') + monkeypatch.setenv('REDIS_HOST', 'redis') + monkeypatch.setenv('REDIS_PORT', '4012') path = tmp_path / 'config.env' path.write_text(DOTENV_CONTENTS) - path.write_text('APP_NAME=supertest-${ENVIRONMENT}-1') + path.write_text( + 'APP_NAME=supertest-${ENVIRONMENT}-1\n' + # make sure more than one variable is possible + 'REDIS_URL=https://${REDIS_HOST}:${REDIS_PORT}\n' + ) store = configstore.Store([ configstore.EnvVarBackend(),