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

[bug] Testing and mocking docs are wrong #264

Closed
anxodio opened this issue Nov 20, 2019 · 15 comments
Closed

[bug] Testing and mocking docs are wrong #264

anxodio opened this issue Nov 20, 2019 · 15 comments

Comments

@anxodio
Copy link

anxodio commented Nov 20, 2019

Describe the bug
The docs in https://dynaconf.readthedocs.io/en/latest/guides/testing.html explain how to test with dynaconf. The point is that if you follow the explanation, you will see AttributeError: 'DynaconfDict' object has no attribute 'current_env'

To Reproduce

Just try to follow the steps in https://dynaconf.readthedocs.io/en/latest/guides/testing.html

Expected behavior
The code don't fail and the mock can be used.

Debug output

Debug Output
Traceback (most recent call last):
  File "lalala.py", line 5, in <module>
    toml_loader.load(mocked_settings, filename="test_conf.toml", env="testing")
  File "/home/angel/.virtualenvs/navi-Pag0EvBg/lib/python3.6/site-packages/dynaconf/loaders/toml_loader.py", line 38, in load
    loader.load(filename=filename, key=key, silent=silent)
  File "/home/angel/.virtualenvs/navi-Pag0EvBg/lib/python3.6/site-packages/dynaconf/loaders/base.py", line 69, in load
    env_list = build_env_list(self.obj, self.env)
  File "/home/angel/.virtualenvs/navi-Pag0EvBg/lib/python3.6/site-packages/dynaconf/utils/__init__.py", line 220, in build_env_list
    if obj.current_env and obj.current_env not in env_list:
AttributeError: 'DynaconfDict' object has no attribute 'current_env'

Environment (please complete the following information):

  • OS: Ubuntu 18.04
  • Dynaconf Version 2.2
@anxodio anxodio added the bug label Nov 20, 2019
@rochacbruno
Copy link
Member

@rochacbruno
Copy link
Member

def __init__(self, *args, **kwargs):
        self._loaded_files = []
+       self.current_env = kwargs.get('env', 'development')
        super(DynaconfDict, self).__init__(*args, **kwargs)

@hilam
Copy link
Collaborator

hilam commented Dec 9, 2019

I will work on this.

@rochacbruno rochacbruno added this to the 2.2.2 milestone Dec 20, 2019
@rochacbruno rochacbruno added Docs and removed bug labels Dec 20, 2019
@hilam
Copy link
Collaborator

hilam commented Jan 2, 2020

@rochacbruno Your suggestion results in another error. Any other ideas? I'm trying to figure out.

Traceback (most recent call last):
File "/home/hilam/other-projects/dynaconf/dynaconf/loaders/base.py", line 69, in load
env_list = build_env_list(self.obj, self.env)
File "/home/hilam/other-projects/dynaconf/dynaconf/utils/init.py", line 232, in build_env_list
return [env.lower() for env in env_list]
File "/home/hilam/other-projects/dynaconf/dynaconf/utils/init.py", line 232, in
return [env.lower() for env in env_list]
AttributeError: 'NoneType' object has no attribute 'lower'

@rochacbruno
Copy link
Member

@hilam maybe

self.current_env = kwargs.get('env') or 'development'

@sinnedh
Copy link

sinnedh commented Feb 12, 2020

We have the same issue here with additional accessors as as_dict or as_int here:

AttributeError: 'DynaconfDict' object has no attribute 'as_int'

@rochacbruno
Copy link
Member

I think it is time to reimplement the DynaconfDict in a way that it inherits from Settings and overrides some methods to avoid unwanted loads under testing environment.

@rochacbruno rochacbruno added the HIGH High Priority label Feb 12, 2020
@hilam
Copy link
Collaborator

hilam commented Feb 12, 2020

During my attempts to solve it, I tried to inherit from Settings or LazySettings, but it didn't work. Mysterious import errors. As you know the code better, @rochacbruno you may be able to find the solution. I could not.

@rochacbruno rochacbruno modified the milestones: 2.2.3, 2.2.4 Feb 26, 2020
@ximet
Copy link

ximet commented Jun 6, 2020

have the same issue. How I can help with it?

@rochacbruno rochacbruno modified the milestones: 3.0.0, 4.0.0 Sep 12, 2020
@rochacbruno
Copy link
Member

This is a pending issue, we still need a way to have DynaconfDict to be an instance of Dynaconf class or a subclass of it.

Probably we can deprecate the DynaconfDict (alias it to a new class)

@mazzi
Copy link

mazzi commented Dec 14, 2020

Nice insight!
@rochacbruno So actually there's no way to mock settings?
I was digging in the tests but didn't find anything to load a json or a dict and being able to mock tests.

I wrote something like this. Not optimum but for now it works ok for my purposes. Maybe somebody finds it useful.

    from dynaconf import LazySettings
    from dynaconf.loaders.json_loader import load

    mocked_settings = LazySettings(environments=True, ENV_FOR_DYNACONF="DEFAULT")

    data = """
    {
        "default" : {
            "SETTING_ONE": false,
            "SETTING_TWO": "test"
        }
    }
    """
    load(mocked_settings, filename=data)

Thanks!

Another option would be to use Monkeypatch

@arugifa
Copy link

arugifa commented Jan 29, 2021

@mazzi In fact, MonkeyPatching Dynaconf settings in Pytest doesn't work, unfortunately. Setting values don't change that way.

@limdauto
Copy link

I think the easiest way is to dump a settings file to a temporary location and load it. Something like:

@pytest.fixture
def mock_settings_path(tmpdir):
    settings_path = tmpdir.mkdir("test_package").join("settings.py")
    settings_path.write(
        textwrap.dedent(
            f"""
                SETTING_ONE = True
            """
        )
    )
    return str(settings_path) 

And you can use the fixture as follows:

def test_settings_file(mock_settings_path):
    settings = LazySettings(settings_file=mock_settings_path)
    assert SETTING_ONE == True

The beauty of this approach is that you can actually add a Mock to your mock settings file, e.g.

# in your test module
MOCK_SETTING_TWO = MagicMock()

# in your mock settings file
f"""
from {__name__} import MOCK_SETTING_TWO
SETTING_TWO = MOCK_SETTING_TWO
"""

@GerardoGR
Copy link

GerardoGR commented Sep 16, 2021

I haven't had a closer look to the code to see the inner workings of this, but initializing and mocking the object like this:

from unittest.mock import patch

from dynaconf import Dynaconf

from my_module import function_name


@patch("config.settings", Dynaconf(log_level="DEBUG"))
def test_patch(self):
    assert function_name() == "DEBUG"

Gives the expected result when trying to access the setting in function_name like settings.log_level or settings["log_level"]

@stale
Copy link

stale bot commented Jun 2, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jun 2, 2022
@stale stale bot closed this as completed Jul 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants