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/expected? Issue with django override_settings #596

Closed
ivan-gerasin opened this issue Jun 5, 2021 · 2 comments · Fixed by #645
Closed

Bug/expected? Issue with django override_settings #596

ivan-gerasin opened this issue Jun 5, 2021 · 2 comments · Fixed by #645

Comments

@ivan-gerasin
Copy link

Hi, I'm using dynaconf with django and met an issue when using override_settings decorator in test.

    # all correct imports defined, here just a piece of test itsed
    @override_settings(ANY_CONFIG_PARAM='SOME_VAL')
    def test_method_that_use_settings(self):
        # this actually can be any code that call method where somewhere settings.ANY_OTHER_VALUE are used
        # in my case it was django api test client
        print(settings.ANY_OTHER_VALUE) 
        self.assertTrue(True) # just to have any assert

And I got AttributeError. Last part of the stacktrace:

    # all trace before this depends on where settings.ANY_OTHER_VALUE is used. This lines down below are same for all cases
  File "/home/igerasin/projects/project-alpha/venv/lib/python3.8/site-packages/dynaconf/base.py", line 158, in __getattr__
    self._wrapped._fresh
  File "/home/igerasin/projects/project-alpha/venv/lib/python3.8/site-packages/django/conf/__init__.py", line 242, in __getattr__
    raise AttributeError
AttributeError

Is it expected behavior? How can I correctly use override_settings with dynaconf?
Thanks!

@whg517
Copy link
Contributor

whg517 commented Jun 17, 2021

I got same issue. And this is a bug.

I use pytest-django, when i use settings fixture to override conf in some test case, i got AttributeError .

analysis

Django code logic

In django.test.utils.py

class override_settings(TestContextDecorator):
    """
    Act as either a decorator or a context manager. If it's a decorator, take a
    function and return a wrapped function. If it's a contextmanager, use it
    with the ``with`` statement. In either event, entering/exiting are called
    before and after, respectively, the function/block is executed.
    """
    enable_exception = None

    def __init__(self, **kwargs):
        self.options = kwargs
        super().__init__()

    def enable(self):
        # Keep this code at the beginning to leave the settings unchanged
        # in case it raises an exception because INSTALLED_APPS is invalid.
        if 'INSTALLED_APPS' in self.options:
            try:
                apps.set_installed_apps(self.options['INSTALLED_APPS'])
            except Exception:
                apps.unset_installed_apps()
                raise
        override = UserSettingsHolder(settings._wrapped)
        for key, new_value in self.options.items():
            setattr(override, key, new_value)
        self.wrapped = settings._wrapped
        settings._wrapped = override
        for key, new_value in self.options.items():
            try:
                setting_changed.send(
                    sender=settings._wrapped.__class__,
                    setting=key, value=new_value, enter=True,
                )
            except Exception as exc:
                self.enable_exception = exc
                self.disable()

The settings._wrapped is UserSettingsHolder object.

And django.conf.__init__.py::UserSettingsHolder class

class UserSettingsHolder:
    """Holder for user configured settings."""
    # SETTINGS_MODULE doesn't make much sense in the manually configured
    # (standalone) case.
    SETTINGS_MODULE = None

    def __init__(self, default_settings):
        """
        Requests for configuration variables not in this class are satisfied
        from the module specified in default_settings (if possible).
        """
        self.__dict__['_deleted'] = set()
        self.default_settings = default_settings

    def __getattr__(self, name):
        if not name.isupper() or name in self._deleted:
            raise AttributeError
        return getattr(self.default_settings, name)

If you get a attr is not upper, will raise a AttributeError .

Dynaconf code logic

In dynaconf.base.py::LazySettings class

https://github.com/rochacbruno/dynaconf/blob/6c6fda4950a1a403b71503c8940692aeb3725cdf/dynaconf/base.py#L116-L123

When you get a attr, dynaconf will get it from settings._wrapped, but now settings._wrapped is django.conf.__init__.py::UserSettingsHolder .

So there's an exception.


I knew what the problem was, and I wanted to fix it. But I'm not clear about the complex logic in Dynaconf's 'Settings' class, and I don't have much time to understand the source code at this stage, so I won't commit PR. But I hope this problem can be fixed soon.

@rochacbruno
Copy link
Member

Solution is proposed in #643

@rochacbruno rochacbruno added this to the 3.1.5 milestone Aug 19, 2021
rochacbruno added a commit that referenced this issue Aug 20, 2021
@rochacbruno rochacbruno linked a pull request Aug 20, 2021 that will close this issue
rochacbruno added a commit that referenced this issue Aug 20, 2021
* Fix #596 django.test.override issue

* Fix CI side effects
rochacbruno added a commit that referenced this issue Aug 20, 2021
* Fix #596 django.test.override issue

* Fix CI side effects
rochacbruno added a commit that referenced this issue Aug 20, 2021
Shortlog of commits since last release:

    Bruno Rocha (4):
          Fix #595 namedtuples are no more converted to BoxList (#623)
          fix #596 django override (#645)
          fix #491 pytest django Fix #491 pytest and django (#646)
          Delete requirements.txt

    FrankBattaglia (1):
          fix dict iterator methods for flask DynaconfConfig (#581)

    Robert Rosca (1):
          Add a warning if `--env` is passed to `init` (#629)

    Tanya Tereshchenko (1):
          Do not search anywhere if the absolute path to a file provided (#570)
rochacbruno added a commit that referenced this issue Sep 9, 2021
Shortlog of commits since last release:

    Ambient Lighter (1):
          Fix typo (#647)

    Bruno Rocha (19):
          Release version 3.1.4
          demo link (#546)
          removed release_notes from the docs. (#550)
          HOTFIX: Add coverage for 2 lines on validators.
          Fix #595 namedtuples are no more converted to BoxList (#623)
          Fix black issues (#631)
          Update FUNDING.yml
          description and type annotation for validator (#634)
          Add myoy and pre-commit to CI (#635)
          Update codaci badge (#636)
          Remove dependabot (this project has no dependencies)
          fix #596 django override (#645)
          fix #491 pytest django Fix #491 pytest and django (#646)
          Delete requirements.txt
          Update FUNDING.yml
          Add support for dynaconf_hooks(post) issue #654 (#655)
          Move to Github Actions (#656)
          Bye Azure (#657)
          Bump dev version

    FrankBattaglia (1):
          fix dict iterator methods for flask DynaconfConfig (#581)

    Jacob Callahan (1):
          Add the ability for selective validation (#549)

    Kamil Gałuszka (1):
          Add support for Python 3.9 and remove Ubuntu 16.04 that is deprecated in Azure Pipelines (#618)

    Konstantin (2):
          Update configuration.md (#553)
          Update configuration.md (#554)

    Linus Torvalds (1):
          Fix a typo in the docs

    Martin Thoma (1):
          Add type annotations for dynaconf.utils (#450)

    Nicholas Dentandt (1):
          feat: add filter strategy with PrefixFilter (#625)

    Robert Rosca (1):
          Add a warning if `--env` is passed to `init` (#629)

    Tanya Tereshchenko (1):
          Do not search anywhere if the absolute path to a file provided (#570)

    Yusuf Kaka (1):
          Added an example using FastAPI (#571)

    dependabot-preview[bot] (2):
          Bump mkdocs-material from 7.0.5 to 7.0.6 (#552)
          Upgrade to GitHub-native Dependabot (#574)

    puntonim (1):
          Fix typo (#588)
rochacbruno added a commit that referenced this issue Sep 9, 2021
Shortlog of commits since last release:

    Ambient Lighter (1):
          Fix typo (#647)

    Bruno Rocha (19):
          Release version 3.1.4
          demo link (#546)
          removed release_notes from the docs. (#550)
          HOTFIX: Add coverage for 2 lines on validators.
          Fix #595 namedtuples are no more converted to BoxList (#623)
          Fix black issues (#631)
          Update FUNDING.yml
          description and type annotation for validator (#634)
          Add myoy and pre-commit to CI (#635)
          Update codaci badge (#636)
          Remove dependabot (this project has no dependencies)
          fix #596 django override (#645)
          fix #491 pytest django Fix #491 pytest and django (#646)
          Delete requirements.txt
          Update FUNDING.yml
          Add support for dynaconf_hooks(post) issue #654 (#655)
          Move to Github Actions (#656)
          Bye Azure (#657)
          Bump dev version

    FrankBattaglia (1):
          fix dict iterator methods for flask DynaconfConfig (#581)

    Jacob Callahan (1):
          Add the ability for selective validation (#549)

    Kamil Gałuszka (1):
          Add support for Python 3.9 and remove Ubuntu 16.04 that is deprecated in Azure Pipelines (#618)

    Konstantin (2):
          Update configuration.md (#553)
          Update configuration.md (#554)

    Linus Torvalds (1):
          Fix a typo in the docs

    Martin Thoma (1):
          Add type annotations for dynaconf.utils (#450)

    Nicholas Dentandt (1):
          feat: add filter strategy with PrefixFilter (#625)

    Robert Rosca (1):
          Add a warning if `--env` is passed to `init` (#629)

    Tanya Tereshchenko (1):
          Do not search anywhere if the absolute path to a file provided (#570)

    Yusuf Kaka (1):
          Added an example using FastAPI (#571)

    dependabot-preview[bot] (2):
          Bump mkdocs-material from 7.0.5 to 7.0.6 (#552)
          Upgrade to GitHub-native Dependabot (#574)

    puntonim (1):
          Fix typo (#588)
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