Incompatible with django-configurations due to the way the settings are imported

See original GitHub issue

Bug report

🐛

What’s wrong

Trying to use django-stubs together with django-configurations is a big pain since the latter interferes and controls how django settings are loaded. By default, the following exception gets thrown when trying to run mypy:

(mypackage-vfeg9Sk1-py3.6) ➜  mypackage IN-3486 ✗ python -m mypy -p src.mypackage                                                       
Error constructing plugin instance of NewSemanalDjangoPlugin

Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/mypy/__main__.py", line 12, in <module>
    main(None, sys.stdout, sys.stderr)
  File "mypy/main.py", line 89, in main
  File "mypy/build.py", line 180, in build
  File "mypy/build.py", line 227, in _build
  File "mypy/build.py", line 465, in load_plugins
  File "mypy/build.py", line 443, in load_plugins_from_config
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/mypy_django_plugin/main.py", line 80, in __init__
    self.django_context = DjangoContext(django_settings_module)
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/mypy_django_plugin/django/context.py", line 88, in __init__
    apps, settings = initialize_django(self.django_settings_module)
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/mypy_django_plugin/django/context.py", line 70, in initialize_django
    settings._setup()
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/django/conf/__init__.py", line 66, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/django/conf/__init__.py", line 157, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/sarunas/Documents/projects/mypackage/mypackage/project/settings.py", line 6, in <module>
    from mypackage.settings import Base, IntegratedTests
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/mypackage/settings.py", line 26, in <module>
    class Base(Configuration):  # pylint: disable=no-init
  File "/home/sarunas/.cache/pypoetry/virtualenvs/mypackage-vfeg9Sk1-py3.6/lib/python3.6/site-packages/configurations/base.py", line 28, in __new__
    raise ImproperlyConfigured(install_failure)
django.core.exceptions.ImproperlyConfigured: django-configurations settings importer wasn't correctly installed. Please use one of the starter functions to install it as mentioned in the docs: https://django-configurations.readthedocs.io/

That makes sense, since configurations disallows loading the settings manually and requires to run these two calls to configure django, both of them are for example found in manage.py and wsgi.py:

        import configurations
        configurations.setup()

mypy configuration in setup.cfg (it follows [metadata] and [options] package metadata definitions)

[mypy.plugins.django-stubs]
django_settings_module = project.settings

[mypy]
plugins =
    mypy_django_plugin.main

ignore_errors =            false
warn_no_return =           true
strict_equality =          true
strict_optional =          true
warn_return_any =          true
warn_unreachable =         true
implicit_reexport =        false
check_untyped_defs =       true
local_partial_types =      true
warn_unused_ignores =      true
warn_unused_configs =      true
warn_redundant_casts =     true
no_implicit_optional =     true

namespace_packages =       true
fine_grained_incremental = true
show_error_codes =         true

strict =                   true
allow_any_generics =       false
allow_subclassing_any =    true
ignore_missing_imports =   false

[mypy-mypackage.migrations.*]
ignore_errors = true

I tried looking for a workaround which didn’t involve changing neither mypy nor django-stubs, nor django-configurations source files and I’m afraid I have failed. Unfortunately this also blocks DRF stubs from being useful.

How is that should be

django-configurations should be supported and allowed to load django settings if the user uses it (unless it is somehow incompatible with the way the stubs are generated?).

System information

  • OS: “Ubuntu 18.04.4 LTS”
  • python version: 3.6.9
  • django version: 2.2.14
  • mypy version: 0.770
  • django-stubs version: 1.5.0
  • django-configurations version: 2.2

Possible solution

One of possible options would be to include those two calls in mypy_django_plugin.django.context initialize_django call, just before the models get imported:

def initialize_django(settings_module: str) -> Tuple['Apps', 'LazySettings']:
    with temp_environ():
        os.environ['DJANGO_SETTINGS_MODULE'] = settings_module

        # add current directory to sys.path
        sys.path.append(os.getcwd())

        def noop_class_getitem(cls, key):
            return cls
        
        try:
             # or use importlib.import_module, or check whether django uses it
            import configurations
            configurations.setup()
        except ModuleNotFoundError:
            pass

        from django.db import models

        models.QuerySet.__class_getitem__ = classmethod(noop_class_getitem)  # type: ignore
        models.Manager.__class_getitem__ = classmethod(noop_class_getitem)  # type: ignore
        ...

I found that this works for me - though I haven’t tested it extensively yet. I’d be happy to add a PR for this upon your confirmation.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
Niedzwiedzwcommented, Oct 29, 2020

I’m getting that error when trying to run mypy in my project…

2reactions
snejuscommented, Jul 7, 2020

Surely not.

Cool, that’s great. I’ll get this done in the eve.

Read more comments on GitHub >

github_iconTop Results From Across the Web

django-configurations dev documentation
django-configurations helps you organize the configuration of your Django project by providing the glue code to bridge between Django's module based settings ......
Read more >
python/mypy - Gitter
ImproperlyConfigured: django-configurations settings importer wasn't correctly ... I've tried to find something related to this error in github's issues, ...
Read more >
django-configurations Documentation - Read the Docs
django-configurations helps you organize the configuration of your Django project by providing the glue code to.
Read more >
django-configurations Documentation - SILO of research documents
In fact you can easily do something unrelated to settings, like connecting to a database: from configurations import Configuration class Prod(Configuration):.
Read more >
django-pkgconf - PyPI
Yet another application settings helper. ... emails/foo.py from django.conf import settings. service ... Cool style (django-configurations way):
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found