Refs #31180 -- Removed default_app_config application configuration variable per deprecation timeline.

This commit is contained in:
Mariusz Felisiak 2021-09-16 09:06:40 +02:00
parent d25710a625
commit 75d6c4ae6d
11 changed files with 7 additions and 184 deletions

View File

@ -1,10 +1,8 @@
import inspect import inspect
import os import os
import warnings
from importlib import import_module from importlib import import_module
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.deprecation import RemovedInDjango41Warning
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.module_loading import import_string, module_has_submodule from django.utils.module_loading import import_string, module_has_submodule
@ -102,7 +100,6 @@ class AppConfig:
""" """
# create() eventually returns app_config_class(app_name, app_module). # create() eventually returns app_config_class(app_name, app_module).
app_config_class = None app_config_class = None
app_config_name = None
app_name = None app_name = None
app_module = None app_module = None
@ -134,7 +131,6 @@ class AppConfig:
] ]
if len(app_configs) == 1: if len(app_configs) == 1:
app_config_class = app_configs[0][1] app_config_class = app_configs[0][1]
app_config_name = '%s.%s' % (mod_path, app_configs[0][0])
else: else:
# Check if there's exactly one AppConfig subclass, # Check if there's exactly one AppConfig subclass,
# among those that explicitly define default = True. # among those that explicitly define default = True.
@ -151,43 +147,11 @@ class AppConfig:
) )
elif len(app_configs) == 1: elif len(app_configs) == 1:
app_config_class = app_configs[0][1] app_config_class = app_configs[0][1]
app_config_name = '%s.%s' % (mod_path, app_configs[0][0])
# If app_module specifies a default_app_config, follow the link. # Use the default app config class if we didn't find anything.
# default_app_config is deprecated, but still takes over the if app_config_class is None:
# automatic detection for backwards compatibility during the app_config_class = cls
# deprecation period. app_name = entry
try:
new_entry = app_module.default_app_config
except AttributeError:
# Use the default app config class if we didn't find anything.
if app_config_class is None:
app_config_class = cls
app_name = entry
else:
message = (
'%r defines default_app_config = %r. ' % (entry, new_entry)
)
if new_entry == app_config_name:
message += (
'Django now detects this configuration automatically. '
'You can remove default_app_config.'
)
else:
message += (
"However, Django's automatic detection %s. You should "
"move the default config class to the apps submodule "
"of your application and, if this module defines "
"several config classes, mark the default one with "
"default = True." % (
"picked another configuration, %r" % app_config_name
if app_config_name
else "did not find this configuration"
)
)
warnings.warn(message, RemovedInDjango41Warning, stacklevel=2)
entry = new_entry
app_config_class = None
# If import_string succeeds, entry is an app config class. # If import_string succeeds, entry is an app config class.
if app_config_class is None: if app_config_class is None:

View File

@ -255,3 +255,5 @@ to remove usage of these features.
* The ``whitelist`` argument and ``domain_whitelist`` attribute of * The ``whitelist`` argument and ``domain_whitelist`` attribute of
``django.core.validators.EmailValidator`` are removed. ``django.core.validators.EmailValidator`` are removed.
* The ``default_app_config`` application configuration variable is removed.

View File

@ -1 +0,0 @@
default_app_config = 'apps.explicit_default_config_app.apps.ExplicitDefaultConfig'

View File

@ -1,5 +0,0 @@
from django.apps import AppConfig
class ExplicitDefaultConfig(AppConfig):
name = 'apps.explicit_default_config_app'

View File

@ -1,7 +0,0 @@
from django.apps import AppConfig
default_app_config = 'apps.explicit_default_config_empty_apps.ExplicitDefaultConfigEmptyApps'
class ExplicitDefaultConfigEmptyApps(AppConfig):
name = 'apps.explicit_default_config_empty_apps'

View File

@ -1 +0,0 @@
default_app_config = 'apps.explicit_default_config_mismatch_app.not_apps.ExplicitDefaultConfigMismatch'

View File

@ -1,5 +0,0 @@
from django.apps import AppConfig
class ImplicitDefaultConfigMismatch(AppConfig):
name = 'apps.explicit_default_config_mismatch_app'

View File

@ -1,5 +0,0 @@
from django.apps import AppConfig
class ExplicitDefaultConfigMismatch(AppConfig):
name = 'apps.explicit_default_config_mismatch_app'

View File

@ -1,7 +0,0 @@
from django.apps import AppConfig
default_app_config = 'apps.explicit_default_config_without_apps.ExplicitDefaultConfigWithoutApps'
class ExplicitDefaultConfigWithoutApps(AppConfig):
name = 'apps.explicit_default_config_without_apps'

View File

@ -5,18 +5,9 @@ from django.apps.registry import Apps
from django.contrib.admin.models import LogEntry from django.contrib.admin.models import LogEntry
from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured
from django.db import models from django.db import models
from django.test import SimpleTestCase, ignore_warnings, override_settings from django.test import SimpleTestCase, override_settings
from django.test.utils import extend_sys_path, isolate_apps from django.test.utils import extend_sys_path, isolate_apps
from django.utils.deprecation import RemovedInDjango41Warning
from .explicit_default_config_app.apps import ExplicitDefaultConfig
from .explicit_default_config_empty_apps import ExplicitDefaultConfigEmptyApps
from .explicit_default_config_mismatch_app.not_apps import (
ExplicitDefaultConfigMismatch,
)
from .explicit_default_config_without_apps import (
ExplicitDefaultConfigWithoutApps,
)
from .models import SoAlternative, TotallyNormal, new_apps from .models import SoAlternative, TotallyNormal, new_apps
from .one_config_app.apps import OneConfig from .one_config_app.apps import OneConfig
from .two_configs_one_default_app.apps import TwoConfig from .two_configs_one_default_app.apps import TwoConfig
@ -511,106 +502,3 @@ class NamespacePackageAppTests(SimpleTestCase):
with self.settings(INSTALLED_APPS=['nsapp.apps.NSAppConfig']): with self.settings(INSTALLED_APPS=['nsapp.apps.NSAppConfig']):
app_config = apps.get_app_config('nsapp') app_config = apps.get_app_config('nsapp')
self.assertEqual(app_config.path, self.app_path) self.assertEqual(app_config.path, self.app_path)
class DeprecationTests(SimpleTestCase):
@ignore_warnings(category=RemovedInDjango41Warning)
def test_explicit_default_app_config(self):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_app']):
config = apps.get_app_config('explicit_default_config_app')
self.assertIsInstance(config, ExplicitDefaultConfig)
def test_explicit_default_app_config_warning(self):
"""
Load an app that specifies a default AppConfig class matching the
autodetected one.
"""
msg = (
"'apps.explicit_default_config_app' defines default_app_config = "
"'apps.explicit_default_config_app.apps.ExplicitDefaultConfig'. "
"Django now detects this configuration automatically. You can "
"remove default_app_config."
)
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_app']):
pass
with ignore_warnings(category=RemovedInDjango41Warning):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_app']):
self.assertIsInstance(
apps.get_app_config('explicit_default_config_app'),
ExplicitDefaultConfig,
)
def test_explicit_default_app_config_mismatch(self):
"""
Load an app that specifies a default AppConfig class not matching the
autodetected one.
"""
msg = (
"'apps.explicit_default_config_mismatch_app' defines "
"default_app_config = 'apps.explicit_default_config_mismatch_app."
"not_apps.ExplicitDefaultConfigMismatch'. However, Django's "
"automatic detection picked another configuration, 'apps."
"explicit_default_config_mismatch_app.apps."
"ImplicitDefaultConfigMismatch'. You should move the default "
"config class to the apps submodule of your application and, if "
"this module defines several config classes, mark the default one "
"with default = True."
)
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_mismatch_app']):
pass
with ignore_warnings(category=RemovedInDjango41Warning):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_mismatch_app']):
self.assertIsInstance(
apps.get_app_config('explicit_default_config_mismatch_app'),
ExplicitDefaultConfigMismatch,
)
def test_explicit_default_app_config_empty_apps(self):
"""
Load an app that specifies a default AppConfig class in __init__ and
have an empty apps module.
"""
msg = (
"'apps.explicit_default_config_empty_apps' defines "
"default_app_config = 'apps.explicit_default_config_empty_apps."
"ExplicitDefaultConfigEmptyApps'. However, Django's automatic "
"detection did not find this configuration. You should move the "
"default config class to the apps submodule of your application "
"and, if this module defines several config classes, mark the "
"default one with default = True."
)
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_empty_apps']):
pass
with ignore_warnings(category=RemovedInDjango41Warning):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_empty_apps']):
self.assertIsInstance(
apps.get_app_config('explicit_default_config_empty_apps'),
ExplicitDefaultConfigEmptyApps,
)
def test_explicit_default_app_config_without_apps(self):
"""
Load an app that specifies a default AppConfig class in __init__ and do
not have an apps module.
"""
msg = (
"'apps.explicit_default_config_without_apps' defines "
"default_app_config = 'apps.explicit_default_config_without_apps."
"ExplicitDefaultConfigWithoutApps'. However, Django's automatic "
"detection did not find this configuration. You should move the "
"default config class to the apps submodule of your application "
"and, if this module defines several config classes, mark the "
"default one with default = True."
)
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_without_apps']):
pass
with ignore_warnings(category=RemovedInDjango41Warning):
with self.settings(INSTALLED_APPS=['apps.explicit_default_config_without_apps']):
self.assertIsInstance(
apps.get_app_config('explicit_default_config_without_apps'),
ExplicitDefaultConfigWithoutApps,
)