diff --git a/README.md b/README.md index 28fbd1863..3b19469c9 100644 --- a/README.md +++ b/README.md @@ -74,3 +74,18 @@ Otherwise, custom type will be created in mypy, named `MyUser__MyUserManager`, w We have Gitter here: If you think you have more generic typing issue, please refer to https://github.com/python/mypy and their Gitter. + + +### Django-configurations support + +When using you will need to set `django_configuration` in the `[mypy.plugins.django-stubs]` section. + +```ini +[mypy] +strict_optional = True + +; this one is new +[mypy.plugins.django-stubs] +django_settings_module = mysettings +django_configuration = ProductionConfiguration +``` diff --git a/mypy_django_plugin/django/context.py b/mypy_django_plugin/django/context.py index 3170696e3..1a7d72cde 100644 --- a/mypy_django_plugin/django/context.py +++ b/mypy_django_plugin/django/context.py @@ -41,10 +41,13 @@ def temp_environ(): os.environ.update(environ) -def initialize_django(settings_module: str) -> Tuple['Apps', 'LazySettings']: +def initialize_django(settings_module: str, configuration: Optional[str] = None) -> Tuple['Apps', 'LazySettings']: with temp_environ(): os.environ['DJANGO_SETTINGS_MODULE'] = settings_module + if configuration is not None: + os.environ['DJANGO_CONFIGURATION'] = configuration + def noop_class_getitem(cls, key): return cls @@ -60,7 +63,13 @@ def noop_class_getitem(cls, key): apps.get_swappable_settings_name.cache_clear() # type: ignore if not settings.configured: - settings._setup() + # we are not using django configuration + if configuration is None: + settings._setup() + else: + from configurations import importer # type: ignore + importer.install(check_options=True) + settings._setup() apps.populate(settings.INSTALLED_APPS) @@ -182,13 +191,14 @@ def resolve_lookup(self, model_cls: Type[Model], lookup: str) -> Field: class DjangoContext: - def __init__(self, django_settings_module: str) -> None: + def __init__(self, django_settings_module: str, django_configuration: Optional[str] = None) -> None: self.fields_context = DjangoFieldsContext(self) self.lookups_context = DjangoLookupsContext(self) self.django_settings_module = django_settings_module + self.django_configuration = django_configuration - apps, settings = initialize_django(self.django_settings_module) + apps, settings = initialize_django(self.django_settings_module, self.django_configuration) self.apps_registry = apps self.settings = settings diff --git a/mypy_django_plugin/main.py b/mypy_django_plugin/main.py index 3e485da02..720ea3681 100644 --- a/mypy_django_plugin/main.py +++ b/mypy_django_plugin/main.py @@ -69,11 +69,35 @@ def extract_django_settings_module(config_file_path: Optional[str]) -> str: return django_settings_module +def extract_django_configuration(config_file_path: Optional[str]) -> Optional[str]: + errors = Errors() + if config_file_path is None: + errors.report(0, None, + "'django_settings_module' is not set: no mypy config file specified") + errors.raise_error() + + parser = configparser.ConfigParser() + parser.read(config_file_path) # type: ignore + + if not parser.has_section('mypy.plugins.django-stubs'): + errors.report(0, None, + "'django_configuration' is not set: no section [mypy.plugins.django-stubs]", + file=config_file_path) + errors.raise_error() + if not parser.has_option('mypy.plugins.django-stubs', 'django_configuration'): + return None + + django_configuration = parser.get('mypy.plugins.django-stubs', + 'django_configuration').strip('\'"') + return django_configuration + + class NewSemanalDjangoPlugin(Plugin): def __init__(self, options: Options) -> None: super().__init__(options) django_settings_module = extract_django_settings_module(options.config_file) - self.django_context = DjangoContext(django_settings_module) + django_configuration = extract_django_configuration(options.config_file) + self.django_context = DjangoContext(django_settings_module, django_configuration) def _get_current_queryset_bases(self) -> Dict[str, int]: model_sym = self.lookup_fully_qualified(fullnames.QUERYSET_CLASS_FULLNAME)