summaryrefslogtreecommitdiff
path: root/django/apps/base.py
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2014-01-24 22:43:00 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2014-01-25 10:41:56 +0100
commit2ff93e027c7b35378cc450a926bc2e4a446cacf0 (patch)
treea6c95d694eadb4bd66b37e9bedad5047d1428d69 /django/apps/base.py
parent29ddae7436e84f4713c7babeabdf9a1fa62d6543 (diff)
Fixed #21829 -- Added default AppConfigs.
Thanks Russell for the report, Marc for the initial patch, Carl for the final review, and everyone who contributed to the design discussion.
Diffstat (limited to 'django/apps/base.py')
-rw-r--r--django/apps/base.py69
1 files changed, 40 insertions, 29 deletions
diff --git a/django/apps/base.py b/django/apps/base.py
index ea28797108..2ae40e2454 100644
--- a/django/apps/base.py
+++ b/django/apps/base.py
@@ -61,13 +61,12 @@ class AppConfig(object):
Factory that creates an app config from an entry in INSTALLED_APPS.
"""
try:
- # If import_module succeeds, entry is a path to an app module.
+ # If import_module succeeds, entry is a path to an app module,
+ # which may specify an app config class with default_app_config.
# Otherwise, entry is a path to an app config class or an error.
module = import_module(entry)
except ImportError:
- # Avoid django.utils.module_loading.import_by_path because it
- # masks errors -- it reraises ImportError as ImproperlyConfigured.
mod_path, _, cls_name = entry.rpartition('.')
# Raise the original exception when entry cannot be a path to an
@@ -75,39 +74,51 @@ class AppConfig(object):
if not mod_path:
raise
- mod = import_module(mod_path)
+ else:
try:
- cls = getattr(mod, cls_name)
+ # If this works, the app module specifies an app config class.
+ entry = module.default_app_config
except AttributeError:
- # Emulate the error that "from <mod_path> import <cls_name>"
- # would raise when <mod_path> exists but not <cls_name>, with
- # more context (Python just says "cannot import name ...").
- raise ImportError(
- "cannot import name '%s' from '%s'" % (cls_name, mod_path))
+ # Otherwise, it simply uses the default app config class.
+ return cls(entry, module)
+ else:
+ mod_path, _, cls_name = entry.rpartition('.')
- # Check for obvious errors. (This check prevents duck typing, but
- # it could be removed if it became a problem in practice.)
- if not issubclass(cls, AppConfig):
- raise ImproperlyConfigured(
- "'%s' isn't a subclass of AppConfig." % entry)
+ # If we're reaching this point, we must load the app config class
+ # located at <mod_path>.<cls_name>.
- # Obtain app name here rather than in AppClass.__init__ to keep
- # all error checking for entries in INSTALLED_APPS in one place.
- try:
- app_name = cls.name
- except AttributeError:
- raise ImproperlyConfigured(
- "'%s' must supply a name attribute." % entry)
+ # Avoid django.utils.module_loading.import_by_path because it
+ # masks errors -- it reraises ImportError as ImproperlyConfigured.
+ mod = import_module(mod_path)
+ try:
+ cls = getattr(mod, cls_name)
+ except AttributeError:
+ # Emulate the error that "from <mod_path> import <cls_name>"
+ # would raise when <mod_path> exists but not <cls_name>, with
+ # more context (Python just says "cannot import name ...").
+ raise ImportError(
+ "cannot import name '%s' from '%s'" % (cls_name, mod_path))
- # Ensure app_name points to a valid module.
- app_module = import_module(app_name)
+ # Check for obvious errors. (This check prevents duck typing, but
+ # it could be removed if it became a problem in practice.)
+ if not issubclass(cls, AppConfig):
+ raise ImproperlyConfigured(
+ "'%s' isn't a subclass of AppConfig." % entry)
- # Entry is a path to an app config class.
- return cls(app_name, app_module)
+ # Obtain app name here rather than in AppClass.__init__ to keep
+ # all error checking for entries in INSTALLED_APPS in one place.
+ try:
+ app_name = cls.name
+ except AttributeError:
+ raise ImproperlyConfigured(
+ "'%s' must supply a name attribute." % entry)
+
+ # Ensure app_name points to a valid module.
+ app_module = import_module(app_name)
+
+ # Entry is a path to an app config class.
+ return cls(app_name, app_module)
- else:
- # Entry is a path to an app module.
- return cls(entry, module)
def get_model(self, model_name):
"""