summaryrefslogtreecommitdiff
path: root/django
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
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')
-rw-r--r--django/apps/base.py69
-rw-r--r--django/conf/project_template/project_name/settings.py2
-rw-r--r--django/contrib/admin/__init__.py5
-rw-r--r--django/contrib/admin/apps.py15
-rw-r--r--django/contrib/admin/sites.py2
-rw-r--r--django/contrib/admindocs/__init__.py1
-rw-r--r--django/contrib/auth/__init__.py9
-rw-r--r--django/contrib/auth/apps.py5
-rw-r--r--django/contrib/comments/__init__.py7
-rw-r--r--django/contrib/contenttypes/__init__.py9
-rw-r--r--django/contrib/contenttypes/apps.py6
-rw-r--r--django/contrib/flatpages/__init__.py1
-rw-r--r--django/contrib/formtools/__init__.py1
-rw-r--r--django/contrib/gis/__init__.py3
-rw-r--r--django/contrib/humanize/__init__.py1
-rw-r--r--django/contrib/messages/__init__.py3
-rw-r--r--django/contrib/redirects/__init__.py1
-rw-r--r--django/contrib/sessions/__init__.py1
-rw-r--r--django/contrib/sitemaps/__init__.py3
-rw-r--r--django/contrib/sites/__init__.py1
-rw-r--r--django/contrib/staticfiles/__init__.py1
-rw-r--r--django/contrib/syndication/__init__.py1
-rw-r--r--django/contrib/webdesign/__init__.py1
-rw-r--r--django/core/checks/registry.py3
24 files changed, 97 insertions, 54 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):
"""
diff --git a/django/conf/project_template/project_name/settings.py b/django/conf/project_template/project_name/settings.py
index 198a3e0d92..efe8091e81 100644
--- a/django/conf/project_template/project_name/settings.py
+++ b/django/conf/project_template/project_name/settings.py
@@ -30,7 +30,7 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
- 'django.contrib.admin.apps.AdminConfig',
+ 'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
diff --git a/django/contrib/admin/__init__.py b/django/contrib/admin/__init__.py
index 530badf1df..2218dfd23f 100644
--- a/django/contrib/admin/__init__.py
+++ b/django/contrib/admin/__init__.py
@@ -1,6 +1,5 @@
# ACTION_CHECKBOX_NAME is unused, but should stay since its import from here
# has been referenced in documentation.
-from django.contrib.admin.checks import check_admin_app
from django.contrib.admin.decorators import register
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
@@ -9,7 +8,6 @@ from django.contrib.admin.filters import (ListFilter, SimpleListFilter,
FieldListFilter, BooleanFieldListFilter, RelatedFieldListFilter,
ChoicesFieldListFilter, DateFieldListFilter, AllValuesFieldListFilter)
from django.contrib.admin.sites import AdminSite, site
-from django.core import checks
from django.utils.module_loading import autodiscover_modules
__all__ = [
@@ -24,4 +22,5 @@ __all__ = [
def autodiscover():
autodiscover_modules('admin', register_to=site)
-checks.register('admin')(check_admin_app)
+
+default_app_config = 'django.contrib.admin.apps.AdminConfig'
diff --git a/django/contrib/admin/apps.py b/django/contrib/admin/apps.py
index a8f0e91ea6..93dab8a787 100644
--- a/django/contrib/admin/apps.py
+++ b/django/contrib/admin/apps.py
@@ -1,11 +1,22 @@
from django.apps import AppConfig
-
+from django.core import checks
+from django.contrib.admin.checks import check_admin_app
from django.utils.translation import ugettext_lazy as _
-class AdminConfig(AppConfig):
+class SimpleAdminConfig(AppConfig):
+ """Simple AppConfig which does not do automatic discovery."""
+
name = 'django.contrib.admin'
verbose_name = _("administration")
def ready(self):
+ checks.register('admin')(check_admin_app)
+
+
+class AdminConfig(SimpleAdminConfig):
+ """The default AppConfig for admin which does autodiscovery."""
+
+ def ready(self):
+ super(AdminConfig, self).ready()
self.module.autodiscover()
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index ba7c38dcad..f25055baf7 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -161,7 +161,7 @@ class AdminSite(object):
installed, as well as the auth context processor.
"""
if not apps.is_installed('django.contrib.admin'):
- raise ImproperlyConfigured("Put 'django.contrib.admin.apps.AdminConfig' in "
+ raise ImproperlyConfigured("Put 'django.contrib.admin' in "
"your INSTALLED_APPS setting in order to use the admin application.")
if not apps.is_installed('django.contrib.contenttypes'):
raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in "
diff --git a/django/contrib/admindocs/__init__.py b/django/contrib/admindocs/__init__.py
index e69de29bb2..733519ac54 100644
--- a/django/contrib/admindocs/__init__.py
+++ b/django/contrib/admindocs/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.admindocs.apps.AdminDocsConfig'
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index 24c870dafe..77b2482e31 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -2,8 +2,6 @@ import inspect
import re
from django.conf import settings
-from django.contrib.auth.checks import check_user_model
-from django.core import checks
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.utils.module_loading import import_by_path
from django.middleware.csrf import rotate_token
@@ -15,10 +13,6 @@ BACKEND_SESSION_KEY = '_auth_user_backend'
REDIRECT_FIELD_NAME = 'next'
-# Register the user model checks
-checks.register('models')(check_user_model)
-
-
def load_backend(path):
return import_by_path(path)()
@@ -164,3 +158,6 @@ def get_permission_codename(action, opts):
Returns the codename of the permission for the specified action.
"""
return '%s_%s' % (action, opts.model_name)
+
+
+default_app_config = 'django.contrib.auth.apps.AuthConfig'
diff --git a/django/contrib/auth/apps.py b/django/contrib/auth/apps.py
index e44ad1a0c7..a0389acabe 100644
--- a/django/contrib/auth/apps.py
+++ b/django/contrib/auth/apps.py
@@ -1,4 +1,6 @@
from django.apps import AppConfig
+from django.core import checks
+from django.contrib.auth.checks import check_user_model
from django.utils.translation import ugettext_lazy as _
@@ -6,3 +8,6 @@ from django.utils.translation import ugettext_lazy as _
class AuthConfig(AppConfig):
name = 'django.contrib.auth'
verbose_name = _("authentication and authorization")
+
+ def ready(self):
+ checks.register('models')(check_user_model)
diff --git a/django/contrib/comments/__init__.py b/django/contrib/comments/__init__.py
index 19dd7ef9a1..a62fff1b56 100644
--- a/django/contrib/comments/__init__.py
+++ b/django/contrib/comments/__init__.py
@@ -1,6 +1,6 @@
from importlib import import_module
import warnings
-from django.apps import apps
+from django.apps import apps as django_apps
from django.conf import settings
from django.core import urlresolvers
from django.core.exceptions import ImproperlyConfigured
@@ -16,7 +16,7 @@ def get_comment_app():
Get the comment app (i.e. "django.contrib.comments") as defined in the settings
"""
try:
- app_config = apps.get_app_config(get_comment_app_name().rpartition(".")[2])
+ app_config = django_apps.get_app_config(get_comment_app_name().rpartition(".")[2])
except LookupError:
raise ImproperlyConfigured("The COMMENTS_APP (%r) "
"must be in INSTALLED_APPS" % settings.COMMENTS_APP)
@@ -85,3 +85,6 @@ def get_approve_url(comment):
else:
return urlresolvers.reverse("django.contrib.comments.views.moderation.approve",
args=(comment.id,))
+
+
+default_app_config = 'django.contrib.comments.apps.CommentsConfig'
diff --git a/django/contrib/contenttypes/__init__.py b/django/contrib/contenttypes/__init__.py
index 5a04849f06..9789f36eff 100644
--- a/django/contrib/contenttypes/__init__.py
+++ b/django/contrib/contenttypes/__init__.py
@@ -1,8 +1 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.contrib.contenttypes.checks import check_generic_foreign_keys
-from django.core import checks
-
-
-checks.register('models')(check_generic_foreign_keys)
+default_app_config = 'django.contrib.contenttypes.apps.ContentTypesConfig'
diff --git a/django/contrib/contenttypes/apps.py b/django/contrib/contenttypes/apps.py
index 0e55e8d66d..4e515d8a00 100644
--- a/django/contrib/contenttypes/apps.py
+++ b/django/contrib/contenttypes/apps.py
@@ -1,8 +1,12 @@
from django.apps import AppConfig
-
+from django.contrib.contenttypes.checks import check_generic_foreign_keys
+from django.core import checks
from django.utils.translation import ugettext_lazy as _
class ContentTypesConfig(AppConfig):
name = 'django.contrib.contenttypes'
verbose_name = _("content types")
+
+ def ready(self):
+ checks.register('models')(check_generic_foreign_keys)
diff --git a/django/contrib/flatpages/__init__.py b/django/contrib/flatpages/__init__.py
index e69de29bb2..865acd855b 100644
--- a/django/contrib/flatpages/__init__.py
+++ b/django/contrib/flatpages/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.flatpages.apps.FlatPagesConfig'
diff --git a/django/contrib/formtools/__init__.py b/django/contrib/formtools/__init__.py
index e69de29bb2..b82588d8e7 100644
--- a/django/contrib/formtools/__init__.py
+++ b/django/contrib/formtools/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.formtools.apps.FormToolsConfig'
diff --git a/django/contrib/gis/__init__.py b/django/contrib/gis/__init__.py
index c996fdfdc2..84b3552ce7 100644
--- a/django/contrib/gis/__init__.py
+++ b/django/contrib/gis/__init__.py
@@ -4,3 +4,6 @@ if six.PY3:
memoryview = memoryview
else:
memoryview = buffer
+
+
+default_app_config = 'django.contrib.gis.apps.GISConfig'
diff --git a/django/contrib/humanize/__init__.py b/django/contrib/humanize/__init__.py
index e69de29bb2..9ca1642fae 100644
--- a/django/contrib/humanize/__init__.py
+++ b/django/contrib/humanize/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.humanize.apps.HumanizeConfig'
diff --git a/django/contrib/messages/__init__.py b/django/contrib/messages/__init__.py
index 40ba6ea6c7..a0cb24b2d9 100644
--- a/django/contrib/messages/__init__.py
+++ b/django/contrib/messages/__init__.py
@@ -1,2 +1,5 @@
from django.contrib.messages.api import * # NOQA
from django.contrib.messages.constants import * # NOQA
+
+
+default_app_config = 'django.contrib.messages.apps.MessagesConfig'
diff --git a/django/contrib/redirects/__init__.py b/django/contrib/redirects/__init__.py
index e69de29bb2..65364a440b 100644
--- a/django/contrib/redirects/__init__.py
+++ b/django/contrib/redirects/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.redirects.apps.RedirectsConfig'
diff --git a/django/contrib/sessions/__init__.py b/django/contrib/sessions/__init__.py
index e69de29bb2..0382f95d7e 100644
--- a/django/contrib/sessions/__init__.py
+++ b/django/contrib/sessions/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.sessions.apps.SessionsConfig'
diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py
index 4396708098..ee3d22090d 100644
--- a/django/contrib/sitemaps/__init__.py
+++ b/django/contrib/sitemaps/__init__.py
@@ -133,3 +133,6 @@ class GenericSitemap(Sitemap):
if self.date_field is not None:
return getattr(item, self.date_field)
return None
+
+
+default_app_config = 'django.contrib.sitemaps.apps.SiteMapsConfig'
diff --git a/django/contrib/sites/__init__.py b/django/contrib/sites/__init__.py
index e69de29bb2..b554240bb2 100644
--- a/django/contrib/sites/__init__.py
+++ b/django/contrib/sites/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.sites.apps.SitesConfig'
diff --git a/django/contrib/staticfiles/__init__.py b/django/contrib/staticfiles/__init__.py
index e69de29bb2..8a07b83d2f 100644
--- a/django/contrib/staticfiles/__init__.py
+++ b/django/contrib/staticfiles/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.staticfiles.apps.StaticFilesConfig'
diff --git a/django/contrib/syndication/__init__.py b/django/contrib/syndication/__init__.py
index e69de29bb2..2c3f52578d 100644
--- a/django/contrib/syndication/__init__.py
+++ b/django/contrib/syndication/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.syndication.apps.SyndicationConfig'
diff --git a/django/contrib/webdesign/__init__.py b/django/contrib/webdesign/__init__.py
index e69de29bb2..2340116bc8 100644
--- a/django/contrib/webdesign/__init__.py
+++ b/django/contrib/webdesign/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'django.contrib.webdesign.apps.WebDesignConfig'
diff --git a/django/core/checks/registry.py b/django/core/checks/registry.py
index efb5b4b892..21efbf317e 100644
--- a/django/core/checks/registry.py
+++ b/django/core/checks/registry.py
@@ -29,7 +29,8 @@ class CheckRegistry(object):
def inner(check):
check.tags = tags
- self.registered_checks.append(check)
+ if check not in self.registered_checks:
+ self.registered_checks.append(check)
return check
return inner