summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarten Kenbeek <marten.knbk@gmail.com>2018-09-18 18:19:18 +0200
committerTim Graham <timograham@gmail.com>2018-09-26 16:12:21 -0400
commit40c8ffad7249fd37ca1629f06d3ab6b129d84b21 (patch)
treec0d443faee1cb04f95ee2f70f64bce04a010327f
parent2349cbd909c387d2d05cda20ce8d0c63c1b1c6c4 (diff)
Fixed #29768 -- Improved error message when an AppConfig has a typo in INSTALLED_APPS.
-rw-r--r--django/apps/config.py17
-rw-r--r--tests/apps/tests.py16
2 files changed, 27 insertions, 6 deletions
diff --git a/django/apps/config.py b/django/apps/config.py
index aeb47923d8..f5c971fc9c 100644
--- a/django/apps/config.py
+++ b/django/apps/config.py
@@ -118,8 +118,21 @@ class AppConfig:
cls = getattr(mod, cls_name)
except AttributeError:
if module is None:
- # If importing as an app module failed, that error probably
- # contains the most informative traceback. Trigger it again.
+ # If importing as an app module failed, check if the module
+ # contains any valid AppConfigs and show them as choices.
+ # Otherwise, that error probably contains the most informative
+ # traceback, so trigger it again.
+ candidates = sorted(
+ repr(name) for name, candidate in mod.__dict__.items()
+ if isinstance(candidate, type) and
+ issubclass(candidate, AppConfig) and
+ candidate is not AppConfig
+ )
+ if candidates:
+ raise ImproperlyConfigured(
+ "'%s' does not contain a class '%s'. Choices are: %s."
+ % (mod_path, cls_name, ', '.join(candidates))
+ )
import_module(entry)
else:
raise
diff --git a/tests/apps/tests.py b/tests/apps/tests.py
index 2fec1d8b4c..cd22a4d45c 100644
--- a/tests/apps/tests.py
+++ b/tests/apps/tests.py
@@ -81,10 +81,18 @@ class AppsTests(SimpleTestCase):
pass
def test_no_such_app_config(self):
- """
- Tests when INSTALLED_APPS contains an entry that doesn't exist.
- """
- with self.assertRaises(ImportError):
+ msg = "No module named 'apps.NoSuchConfig'"
+ with self.assertRaisesMessage(ImportError, msg):
+ with self.settings(INSTALLED_APPS=['apps.NoSuchConfig']):
+ pass
+
+ def test_no_such_app_config_with_choices(self):
+ msg = (
+ "'apps.apps' does not contain a class 'NoSuchConfig'. Choices are: "
+ "'BadConfig', 'MyAdmin', 'MyAuth', 'NoSuchApp', 'PlainAppsConfig', "
+ "'RelabeledAppsConfig'."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
with self.settings(INSTALLED_APPS=['apps.apps.NoSuchConfig']):
pass