Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Env vars are case sensitive (overriding only uppercase params if written in uppercase) when merge_enabled=True #737

Closed
abalakh opened this issue Apr 12, 2022 · 7 comments · Fixed by #795
Assignees
Milestone

Comments

@abalakh
Copy link

abalakh commented Apr 12, 2022

Let's say i have very simple yaml config with envs:

default:
  my_section:
    my_param: "default settings content"
development:
  my_section:
    my_param: "development settings content"

And i want to override my_param with env variable at some point. What's proper env var name for such case? DYNACONF_MY_SECTION__MY_PARAM works if merge_enabled=False.
However, if merge_enabled=True, DYNACONF_MY_SECTION__MY_PARAM will set my_section.MY_PARAM, not my_section.my_param.
Easy reproducer:

import os
import dynaconf


os.environ["DYNACONF_MY_SECTION__MY_PARAM"] = "env var content"

settings = dynaconf.LazySettings(
	environments=True,
	env="development",
	settings_files=["settings.yaml"],
	merge_enabled=True,
)

print(settings.my_section.my_param)
print(settings.my_section.MY_PARAM)

Running the code returns the following output:

development settings content
env var content

setting merge_enabled=False and re-running the code returns expected output:

env var content
env var content

Documentation is kinda confusing about this behavior, so i'm not 100% sure it's a bug:
On the one hand, https://www.dynaconf.com/envvars/ examples are showing uppercase env vars are correctly recognized:

export DYNACONF_PERSON__IS_ADMIN=true
assert settings.person.is_admin is True

And it works like that with merge_enabled=False
On the other - there's the following line:

Also variable access is case insensitive for the first level key

And there's https://www.dynaconf.com/configuration/#lowercase_read , so it looks like only the first level keys are designed to be case insensitive.

I'm using dynaconf 3.1.7, OS is macOS 12.2.1 if that matters.

@rochacbruno
Copy link
Member

@abalakh this is a bug, env vars are case insensitive only on windows because on windows every env var is forced to be upper case, on linux it should have worked

@rochacbruno
Copy link
Member

@abalakh does it work if you set

DYNACONF_MY_SECTION__my_param=othervalue

??

^that must work, however with all upper must also work if the key already exists in the settings.

@abalakh
Copy link
Author

abalakh commented Apr 12, 2022

@rochacbruno yes, with lowercase everything works. That's what i'm currently using as workaround.

@abalakh abalakh changed the title Env vars are case sensitive when merge_enabled=True. Is that by design? Env vars are case sensitive (overriding only uppercase params if written in uppercase) when merge_enabled=True Apr 13, 2022
@rochacbruno rochacbruno self-assigned this Jun 2, 2022
@rochacbruno rochacbruno added this to the 4.0.0 milestone Jun 6, 2022
@bartolootrit
Copy link

bartolootrit commented Sep 2, 2022

@rochacbruno There is a similar issue. An empty lowercase YAML key value isn't overridden by an uppercase environment variable even when merge_enabled is false:

def test_empty_yaml_key_overriding(tmpdir):
    new_key_value = 'new_key_value'
    os.environ["DYNACONF_LEVEL1__KEY"] = new_key_value
    os.environ["DYNACONF_LEVEL1__KEY2"] = new_key_value
    os.environ["DYNACONF_LEVEL1__key3"] = new_key_value
    os.environ["DYNACONF_LEVEL1__KEY4"] = new_key_value

    tmpdir.join("test.yml").write(
        """
        level1:
          key: key_value
          KEY2:
          key3:
          key4:
        """
    )

    _settings = LazySettings(settings_files=['test.yml'], merge_enabled=False)

    # AssertionError: assert 'key_value' == 'new_key_value' if merge_enabled=True
    assert _settings.level1.key == new_key_value  # OK
    assert _settings.level1.key2 == new_key_value  # OK
    assert _settings.level1.key3 == new_key_value  # OK
    assert _settings.level1.key4 == new_key_value  # AssertionError: assert None == 'new_key_value'

Dynaconf is from the master branch (3.1.10.dev0)

@rochacbruno
Copy link
Member

@bartolootrit I found the problem you described and it has to do with how dictionaries are ordered.

The env_loader is getting data as:

{'LEVEL1': {'KEY4': 'new_key_value', 'key': 'key_value', 'KEY2': None, 'key3': None, 'key4': None}}

And as dicts considers only latest added elements the None is there, I am thinking on a way to solve it.

@rochacbruno
Copy link
Member

rochacbruno commented Sep 2, 2022

I think it might be fixed on this PR #795 @bartolootrit @abalakh

@bartolootrit
Copy link

@rochacbruno Yes. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants