Преглед изворни кода

Dropped AppCache._empty, _with_app and _without_app.

It's now easier to achieve the same effect with modify_settings or
override_settings.
Aymeric Augustin пре 11 година
родитељ
комит
da16bb30ff

+ 0 - 56
django/apps/cache.py

@@ -1,7 +1,6 @@
 "Utilities for loading models and the modules that contain them."
 
 from collections import defaultdict, OrderedDict
-from contextlib import contextmanager
 import os
 import sys
 import warnings
@@ -350,61 +349,6 @@ class AppCache(object):
         """
         self.app_configs = self.stored_app_configs.pop()
 
-    ### DANGEROUS METHODS ### (only used to preserve existing tests)
-
-    def _begin_with_app(self, app_name):
-        # Returns an opaque value that can be passed to _end_with_app().
-        app_config = AppConfig.create(app_name)
-        if app_config.label in self.app_configs:
-            return None
-        else:
-            app_config.import_models(self.all_models[app_config.label])
-            self.app_configs[app_config.label] = app_config
-            return app_config
-
-    def _end_with_app(self, app_config):
-        if app_config is not None:
-            del self.app_configs[app_config.label]
-
-    @contextmanager
-    def _with_app(self, app_name):
-        app_config = self._begin_with_app(app_name)
-        try:
-            yield
-        finally:
-            self._end_with_app(app_config)
-
-    def _begin_without_app(self, app_name):
-        # Returns an opaque value that can be passed to _end_without_app().
-        return self.app_configs.pop(app_name.rpartition(".")[2], None)
-
-    def _end_without_app(self, app_config):
-        if app_config is not None:
-            self.app_configs[app_config.label] = app_config
-
-    @contextmanager
-    def _without_app(self, app_name):
-        app_config = self._begin_without_app(app_name)
-        try:
-            yield
-        finally:
-            self._end_without_app(app_config)
-
-    def _begin_empty(self):
-        app_configs, self.app_configs = self.app_configs, OrderedDict()
-        return app_configs
-
-    def _end_empty(self, app_configs):
-        self.app_configs = app_configs
-
-    @contextmanager
-    def _empty(self):
-        app_configs = self._begin_empty()
-        try:
-            yield
-        finally:
-            self._end_empty(app_configs)
-
     ### DEPRECATED METHODS GO BELOW THIS LINE ###
 
     def load_app(self, app_name):

+ 2 - 3
django/contrib/contenttypes/tests.py

@@ -1,6 +1,5 @@
 from __future__ import unicode_literals
 
-from django.apps import app_cache
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.views import shortcut
 from django.contrib.sites.models import get_current_site
@@ -222,12 +221,12 @@ class ContentTypesTests(TestCase):
         user_ct = ContentType.objects.get_for_model(FooWithUrl)
         obj = FooWithUrl.objects.create(name="john")
 
-        with app_cache._with_app('django.contrib.sites'):
+        with self.modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'}):
             response = shortcut(request, user_ct.id, obj.id)
             self.assertEqual("http://%s/users/john/" % get_current_site(request).domain,
                              response._headers.get("location")[1])
 
-        with app_cache._without_app('django.contrib.sites'):
+        with self.modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'}):
             response = shortcut(request, user_ct.id, obj.id)
             self.assertEqual("http://Example.com/users/john/",
                              response._headers.get("location")[1])

+ 2 - 6
django/contrib/gis/tests/geoapp/test_feeds.py

@@ -3,17 +3,17 @@ from __future__ import unicode_literals
 from unittest import skipUnless
 from xml.dom import minidom
 
-from django.apps import app_cache
 from django.conf import settings
 from django.contrib.sites.models import Site
 from django.contrib.gis.geos import HAS_GEOS
 from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
-from django.test import TestCase
+from django.test import TestCase, modify_settings
 
 if HAS_GEOS:
     from .models import City
 
 
+@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
 @skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
 class GeoFeedTest(TestCase):
 
@@ -21,10 +21,6 @@ class GeoFeedTest(TestCase):
 
     def setUp(self):
         Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
-        self._with_sites = app_cache._begin_with_app('django.contrib.sites')
-
-    def tearDown(self):
-        app_cache._end_with_app(self._with_sites)
 
     def assertChildNodes(self, elem, expected):
         "Taken from syndication/tests.py."

+ 2 - 7
django/contrib/gis/tests/geoapp/test_sitemaps.py

@@ -6,12 +6,11 @@ from xml.dom import minidom
 import os
 import zipfile
 
-from django.apps import app_cache
 from django.conf import settings
 from django.contrib.gis.geos import HAS_GEOS
 from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
 from django.contrib.sites.models import Site
-from django.test import TestCase
+from django.test import TestCase, modify_settings
 from django.test.utils import IgnoreDeprecationWarningsMixin
 from django.utils._os import upath
 
@@ -19,6 +18,7 @@ if HAS_GEOS:
     from .models import City, Country
 
 
+@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
 @skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
 class GeoSitemapTest(IgnoreDeprecationWarningsMixin, TestCase):
 
@@ -27,11 +27,6 @@ class GeoSitemapTest(IgnoreDeprecationWarningsMixin, TestCase):
     def setUp(self):
         super(GeoSitemapTest, self).setUp()
         Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
-        self._with_sites = app_cache._begin_with_app('django.contrib.sites')
-
-    def tearDown(self):
-        app_cache._end_with_app(self._with_sites)
-        super(GeoSitemapTest, self).tearDown()
 
     def assertChildNodes(self, elem, expected):
         "Taken from syndication/tests.py."

+ 32 - 39
django/contrib/messages/tests/base.py

@@ -2,14 +2,14 @@ from unittest import skipUnless
 
 from django import http
 from django.apps import app_cache
-from django.conf import settings, global_settings
+from django.conf import global_settings
 from django.contrib.messages import constants, utils, get_level, set_level
 from django.contrib.messages.api import MessageFailure
 from django.contrib.messages.constants import DEFAULT_LEVELS
 from django.contrib.messages.storage import default_storage, base
 from django.contrib.messages.storage.base import Message
 from django.core.urlresolvers import reverse
-from django.test.utils import override_settings
+from django.test.utils import modify_settings, override_settings
 from django.utils.translation import ugettext_lazy
 
 
@@ -219,55 +219,48 @@ class BaseTests(object):
         for msg in data['messages']:
             self.assertContains(response, msg)
 
-    @override_settings(
-        MIDDLEWARE_CLASSES=filter(
-            lambda m: 'MessageMiddleware' not in m, settings.MIDDLEWARE_CLASSES),
-        TEMPLATE_CONTEXT_PROCESSORS=filter(
-            lambda p: 'context_processors.messages' not in p,
-            settings.TEMPLATE_CONTEXT_PROCESSORS),
-        MESSAGE_LEVEL=constants.DEBUG
+    @modify_settings(
+        INSTALLED_APPS={'remove': 'django.contrib.messages'},
+        MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
+        TEMPLATE_CONTEXT_PROCESSORS={'remove': 'django.contrib.messages.context_processors.messages'},
     )
+    @override_settings(MESSAGE_LEVEL=constants.DEBUG)
     def test_middleware_disabled(self):
         """
         Tests that, when the middleware is disabled, an exception is raised
         when one attempts to store a message.
         """
-        with app_cache._without_app('django.contrib.messages'):
-            data = {
-                'messages': ['Test message %d' % x for x in range(5)],
-            }
-            reverse('django.contrib.messages.tests.urls.show')
-            for level in ('debug', 'info', 'success', 'warning', 'error'):
-                add_url = reverse('django.contrib.messages.tests.urls.add',
-                                  args=(level,))
-                self.assertRaises(MessageFailure, self.client.post, add_url,
-                                  data, follow=True)
-
-    @override_settings(
-        MIDDLEWARE_CLASSES=filter(
-            lambda m: 'MessageMiddleware' not in m, settings.MIDDLEWARE_CLASSES),
-        TEMPLATE_CONTEXT_PROCESSORS=filter(
-            lambda p: 'context_processors.messages' not in p,
-            settings.TEMPLATE_CONTEXT_PROCESSORS),
-        MESSAGE_LEVEL=constants.DEBUG
+        data = {
+            'messages': ['Test message %d' % x for x in range(5)],
+        }
+        reverse('django.contrib.messages.tests.urls.show')
+        for level in ('debug', 'info', 'success', 'warning', 'error'):
+            add_url = reverse('django.contrib.messages.tests.urls.add',
+                              args=(level,))
+            self.assertRaises(MessageFailure, self.client.post, add_url,
+                              data, follow=True)
+
+    @modify_settings(
+        INSTALLED_APPS={'remove': 'django.contrib.messages'},
+        MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
+        TEMPLATE_CONTEXT_PROCESSORS={'remove': 'django.contrib.messages.context_processors.messages'},
     )
     def test_middleware_disabled_fail_silently(self):
         """
         Tests that, when the middleware is disabled, an exception is not
         raised if 'fail_silently' = True
         """
-        with app_cache._without_app('django.contrib.messages'):
-            data = {
-                'messages': ['Test message %d' % x for x in range(5)],
-                'fail_silently': True,
-            }
-            show_url = reverse('django.contrib.messages.tests.urls.show')
-            for level in ('debug', 'info', 'success', 'warning', 'error'):
-                add_url = reverse('django.contrib.messages.tests.urls.add',
-                                  args=(level,))
-                response = self.client.post(add_url, data, follow=True)
-                self.assertRedirects(response, show_url)
-                self.assertFalse('messages' in response.context)
+        data = {
+            'messages': ['Test message %d' % x for x in range(5)],
+            'fail_silently': True,
+        }
+        show_url = reverse('django.contrib.messages.tests.urls.show')
+        for level in ('debug', 'info', 'success', 'warning', 'error'):
+            add_url = reverse('django.contrib.messages.tests.urls.add',
+                              args=(level,))
+            response = self.client.post(add_url, data, follow=True)
+            self.assertRedirects(response, show_url)
+            self.assertFalse('messages' in response.context)
 
     def stored_messages_count(self, storage, response):
         """

+ 10 - 16
django/contrib/redirects/tests.py

@@ -1,22 +1,18 @@
 from django import http
-from django.apps import app_cache
 from django.conf import settings
 from django.contrib.sites.models import Site
 from django.core.exceptions import ImproperlyConfigured
 from django.test import TestCase
-from django.test.utils import override_settings
+from django.test.utils import modify_settings, override_settings
 from django.utils import six
 
 from .middleware import RedirectFallbackMiddleware
 from .models import Redirect
 
 
-@override_settings(
-    APPEND_SLASH=False,
-    MIDDLEWARE_CLASSES=list(settings.MIDDLEWARE_CLASSES) +
-    ['django.contrib.redirects.middleware.RedirectFallbackMiddleware'],
-    SITE_ID=1,
-)
+@modify_settings(MIDDLEWARE_CLASSES={'append':
+    'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
+@override_settings(APPEND_SLASH=False, SITE_ID=1)
 class RedirectTests(TestCase):
 
     def setUp(self):
@@ -57,10 +53,10 @@ class RedirectTests(TestCase):
         response = self.client.get('/initial')
         self.assertEqual(response.status_code, 410)
 
+    @modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
     def test_sites_not_installed(self):
-        with app_cache._without_app('django.contrib.sites'):
-            with self.assertRaises(ImproperlyConfigured):
-                RedirectFallbackMiddleware()
+        with self.assertRaises(ImproperlyConfigured):
+            RedirectFallbackMiddleware()
 
 
 class OverriddenRedirectFallbackMiddleware(RedirectFallbackMiddleware):
@@ -69,11 +65,9 @@ class OverriddenRedirectFallbackMiddleware(RedirectFallbackMiddleware):
     response_redirect_class = http.HttpResponseRedirect
 
 
-@override_settings(
-    MIDDLEWARE_CLASSES=list(settings.MIDDLEWARE_CLASSES) +
-    ['django.contrib.redirects.tests.OverriddenRedirectFallbackMiddleware'],
-    SITE_ID=1,
-)
+@modify_settings(MIDDLEWARE_CLASSES={'append':
+    'django.contrib.redirects.tests.OverriddenRedirectFallbackMiddleware'})
+@override_settings(SITE_ID=1)
 class OverriddenRedirectMiddlewareTests(TestCase):
 
     def setUp(self):

+ 7 - 7
django/contrib/sitemaps/tests/test_http.py

@@ -9,7 +9,7 @@ from django.conf import settings
 from django.contrib.sitemaps import Sitemap, GenericSitemap
 from django.contrib.sites.models import Site
 from django.core.exceptions import ImproperlyConfigured
-from django.test.utils import override_settings
+from django.test import modify_settings, override_settings
 from django.utils.formats import localize
 from django.utils._os import upath
 from django.utils.translation import activate, deactivate
@@ -106,17 +106,17 @@ class HTTPSitemapTests(SitemapTestsBase):
         self.assertContains(response, '<lastmod>%s</lastmod>' % date.today())
         deactivate()
 
+    @modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
     def test_requestsite_sitemap(self):
         # Make sure hitting the flatpages sitemap without the sites framework
         # installed doesn't raise an exception.
-        with app_cache._without_app('django.contrib.sites'):
-            response = self.client.get('/simple/sitemap.xml')
-            expected_content = """<?xml version="1.0" encoding="UTF-8"?>
+        response = self.client.get('/simple/sitemap.xml')
+        expected_content = """<?xml version="1.0" encoding="UTF-8"?>
 <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
 <url><loc>http://testserver/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
 </urlset>
 """ % date.today()
-            self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
+        self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
 
     @skipUnless(app_cache.has_app('django.contrib.sites'),
                 "django.contrib.sites app not installed.")
@@ -128,14 +128,14 @@ class HTTPSitemapTests(SitemapTestsBase):
         Site.objects.all().delete()
         self.assertRaises(ImproperlyConfigured, Sitemap().get_urls)
 
+    @modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
     def test_sitemap_get_urls_no_site_2(self):
         """
         Check we get ImproperlyConfigured when we don't pass a site object to
         Sitemap.get_urls if Site objects exists, but the sites framework is not
         actually installed.
         """
-        with app_cache._without_app('django.contrib.sites'):
-            self.assertRaises(ImproperlyConfigured, Sitemap().get_urls)
+        self.assertRaises(ImproperlyConfigured, Sitemap().get_urls)
 
     def test_sitemap_item(self):
         """

+ 3 - 7
django/contrib/sites/tests.py

@@ -1,22 +1,18 @@
 from __future__ import unicode_literals
 
-from django.apps import app_cache
 from django.conf import settings
 from django.contrib.sites.models import Site, RequestSite, get_current_site
 from django.core.exceptions import ObjectDoesNotExist, ValidationError
 from django.http import HttpRequest
 from django.test import TestCase
-from django.test.utils import override_settings
+from django.test.utils import modify_settings, override_settings
 
 
+@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
 class SitesFrameworkTests(TestCase):
 
     def setUp(self):
         Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
-        self._with_sites = app_cache._begin_with_app('django.contrib.sites')
-
-    def tearDown(self):
-        app_cache._end_with_app(self._with_sites)
 
     def test_save_another(self):
         # Regression for #17415
@@ -67,7 +63,7 @@ class SitesFrameworkTests(TestCase):
         self.assertRaises(ObjectDoesNotExist, get_current_site, request)
 
         # A RequestSite is returned if the sites framework is not installed
-        with app_cache._without_app('django.contrib.sites'):
+        with self.modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'}):
             site = get_current_site(request)
             self.assertTrue(isinstance(site, RequestSite))
             self.assertEqual(site.name, "example.com")

+ 6 - 6
tests/admin_docs/tests.py

@@ -1,13 +1,12 @@
 import unittest
 
-from django.apps import app_cache
 from django.conf import settings
 from django.contrib.sites.models import Site
 from django.contrib.admindocs import utils
 from django.contrib.auth.models import User
 from django.core.urlresolvers import reverse
 from django.test import TestCase
-from django.test.utils import override_settings
+from django.test.utils import modify_settings, override_settings
 
 
 class MiscTests(TestCase):
@@ -17,15 +16,16 @@ class MiscTests(TestCase):
         User.objects.create_superuser('super', None, 'secret')
         self.client.login(username='super', password='secret')
 
+    @modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
+    @override_settings(SITE_ID=None)    # will restore SITE_ID after the test
     def test_no_sites_framework(self):
         """
         Without the sites framework, should not access SITE_ID or Site
         objects. Deleting settings is fine here as UserSettingsHolder is used.
         """
-        with self.settings(SITE_ID=None), app_cache._without_app('django.contrib.sites'):
-            Site.objects.all().delete()
-            del settings.SITE_ID
-            self.client.get('/admindocs/views/')  # should not raise
+        Site.objects.all().delete()
+        del settings.SITE_ID
+        self.client.get('/admindocs/views/')  # should not raise
 
 
 @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))

+ 8 - 9
tests/app_loading/tests.py

@@ -2,9 +2,9 @@ from __future__ import unicode_literals
 
 import os
 import sys
-from unittest import TestCase
 
 from django.apps import app_cache
+from django.test import TestCase
 from django.utils._os import upath
 from django.utils import six
 
@@ -17,10 +17,9 @@ class EggLoadingTest(TestCase):
 
         # The models need to be removed after the test in order to prevent bad
         # interactions with the flush operation in other tests.
-        self._old_models = app_cache.app_configs['app_loading'].models.copy()
+        self._old_models = app_cache.all_models['app_loading'].copy()
 
     def tearDown(self):
-        app_cache.app_configs['app_loading'].models = self._old_models
         app_cache.all_models['app_loading'] = self._old_models
         app_cache._get_models_cache = {}
 
@@ -30,7 +29,7 @@ class EggLoadingTest(TestCase):
         """Models module can be loaded from an app in an egg"""
         egg_name = '%s/modelapp.egg' % self.egg_dir
         sys.path.append(egg_name)
-        with app_cache._with_app('app_with_models'):
+        with self.settings(INSTALLED_APPS=['app_with_models']):
             models_module = app_cache.get_app_config('app_with_models').models_module
             self.assertIsNotNone(models_module)
 
@@ -38,7 +37,7 @@ class EggLoadingTest(TestCase):
         """Loading an app from an egg that has no models returns no models (and no error)"""
         egg_name = '%s/nomodelapp.egg' % self.egg_dir
         sys.path.append(egg_name)
-        with app_cache._with_app('app_no_models'):
+        with self.settings(INSTALLED_APPS=['app_no_models']):
             models_module = app_cache.get_app_config('app_no_models').models_module
             self.assertIsNone(models_module)
 
@@ -46,7 +45,7 @@ class EggLoadingTest(TestCase):
         """Models module can be loaded from an app located under an egg's top-level package"""
         egg_name = '%s/omelet.egg' % self.egg_dir
         sys.path.append(egg_name)
-        with app_cache._with_app('omelet.app_with_models'):
+        with self.settings(INSTALLED_APPS=['omelet.app_with_models']):
             models_module = app_cache.get_app_config('app_with_models').models_module
             self.assertIsNotNone(models_module)
 
@@ -54,7 +53,7 @@ class EggLoadingTest(TestCase):
         """Loading an app with no models from under the top-level egg package generates no error"""
         egg_name = '%s/omelet.egg' % self.egg_dir
         sys.path.append(egg_name)
-        with app_cache._with_app('omelet.app_no_models'):
+        with self.settings(INSTALLED_APPS=['omelet.app_no_models']):
             models_module = app_cache.get_app_config('app_no_models').models_module
             self.assertIsNone(models_module)
 
@@ -63,8 +62,8 @@ class EggLoadingTest(TestCase):
         egg_name = '%s/brokenapp.egg' % self.egg_dir
         sys.path.append(egg_name)
         with six.assertRaisesRegex(self, ImportError, 'modelz'):
-            with app_cache._with_app('broken_app'):
-                app_cache.get_app_config('omelet.app_no_models').models_module
+            with self.settings(INSTALLED_APPS=['broken_app']):
+                pass
 
 
 class GetModelsTest(TestCase):

+ 2 - 8
tests/comment_tests/tests/test_app_api.py

@@ -1,10 +1,9 @@
-from django.apps import app_cache
 from django.conf import settings
 from django.contrib import comments
 from django.contrib.comments.models import Comment
 from django.contrib.comments.forms import CommentForm
 from django.core.exceptions import ImproperlyConfigured
-from django.test.utils import override_settings
+from django.test import modify_settings, override_settings
 from django.utils import six
 
 from . import CommentTestCase
@@ -35,16 +34,11 @@ class CommentAppAPITests(CommentTestCase):
         self.assertEqual(comments.get_approve_url(c), "/approve/12345/")
 
 
+@modify_settings(INSTALLED_APPS={'append': 'comment_tests.custom_comments'})
 @override_settings(COMMENTS_APP='comment_tests.custom_comments')
 class CustomCommentTest(CommentTestCase):
     urls = 'comment_tests.urls'
 
-    def setUp(self):
-        self._with_custom_comments = app_cache._begin_with_app('comment_tests.custom_comments')
-
-    def tearDown(self):
-        app_cache._end_with_app(self._with_custom_comments)
-
     def testGetCommentApp(self):
         from comment_tests import custom_comments
         self.assertEqual(comments.get_comment_app(), custom_comments)

+ 3 - 7
tests/i18n/tests.py

@@ -8,7 +8,6 @@ import os
 import pickle
 from threading import local
 
-from django.apps import app_cache
 from django.conf import settings
 from django.template import Template, Context
 from django.template.base import TemplateSyntaxError
@@ -1039,21 +1038,18 @@ class ResolutionOrderI18NTests(TransRealMixin, TestCase):
 class AppResolutionOrderI18NTests(ResolutionOrderI18NTests):
 
     def test_app_translation(self):
-        # This test relies on an implementation detail, namely the fact that
-        # _with_app adds the app at the list. Adjust the test if this changes.
-
         # Original translation.
         self.assertUgettext('Date/time', 'Datum/Zeit')
 
         # Different translation.
-        with app_cache._with_app('i18n.resolution'):
+        with self.modify_settings(INSTALLED_APPS={'append': 'i18n.resolution'}):
             self.flush_caches()
             activate('de')
 
             # Doesn't work because it's added later in the list.
             self.assertUgettext('Date/time', 'Datum/Zeit')
 
-            with app_cache._without_app('admin'):
+            with self.modify_settings(INSTALLED_APPS={'remove': 'django.contrib.admin'}):
                 self.flush_caches()
                 activate('de')
 
@@ -1068,7 +1064,7 @@ class LocalePathsResolutionOrderI18NTests(ResolutionOrderI18NTests):
         self.assertUgettext('Time', 'LOCALE_PATHS')
 
     def test_locale_paths_override_app_translation(self):
-        with app_cache._with_app('i18n.resolution'):
+        with self.settings(INSTALLED_APPS=['i18n.resolution']):
             self.assertUgettext('Time', 'LOCALE_PATHS')
 
 

+ 4 - 4
tests/invalid_models_tests/tests.py

@@ -3,7 +3,7 @@ import unittest
 
 from django.apps import app_cache
 from django.core.management.validation import get_validation_errors
-from django.test.utils import override_settings
+from django.test import override_settings
 from django.utils.six import StringIO
 
 
@@ -26,14 +26,14 @@ class InvalidModelTestCase(unittest.TestCase):
     # easier to set this up as an override than to require every developer
     # to specify a value in their test settings.
     @override_settings(
+        INSTALLED_APPS=['invalid_models_tests.invalid_models'],
         TEST_SWAPPED_MODEL='invalid_models.ReplacementModel',
         TEST_SWAPPED_MODEL_BAD_VALUE='not-a-model',
         TEST_SWAPPED_MODEL_BAD_MODEL='not_an_app.Target',
     )
     def test_invalid_models(self):
-        with app_cache._with_app("invalid_models_tests.invalid_models"):
-            module = app_cache.get_app_config("invalid_models").models_module
-            get_validation_errors(self.stdout, module)
+        module = app_cache.get_app_config("invalid_models").models_module
+        get_validation_errors(self.stdout, module)
 
         self.stdout.seek(0)
         error_log = self.stdout.read()

+ 1 - 2
tests/migrations/test_writer.py

@@ -5,7 +5,6 @@ from __future__ import unicode_literals
 import datetime
 import os
 
-from django.apps import app_cache
 from django.core.validators import RegexValidator, EmailValidator
 from django.db import models, migrations
 from django.db.migrations.writer import MigrationWriter
@@ -123,7 +122,7 @@ class WriterTests(TestCase):
         base_dir = os.path.dirname(os.path.dirname(__file__))
 
         for app in test_apps:
-            with app_cache._with_app(app):
+            with self.modify_settings(INSTALLED_APPS={'append': app}):
                 migration = migrations.Migration('0001_initial', app.split('.')[-1])
                 expected_path = os.path.join(base_dir, *(app.split('.') + ['migrations', '0001_initial.py']))
                 writer = MigrationWriter(migration)

+ 1 - 2
tests/proxy_model_inheritance/tests.py

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import os
 import sys
 
-from django.apps import app_cache
 from django.core.management import call_command
 from django.test import TestCase, TransactionTestCase
 from django.utils._os import upath
@@ -28,7 +27,7 @@ class ProxyModelInheritanceTests(TransactionTestCase):
         sys.path = self.old_sys_path
 
     def test_table_exists(self):
-        with app_cache._with_app('app1'), app_cache._with_app('app2'):
+        with self.modify_settings(INSTALLED_APPS={'append': ['app1', 'app2']}):
             call_command('migrate', verbosity=0)
             from .app1.models import ProxyModel
             from .app2.models import NiceModel

+ 4 - 2
tests/runtests.py

@@ -86,7 +86,7 @@ def get_installed():
 
 def setup(verbosity, test_labels):
     import django
-    from django.apps import app_cache
+    from django.apps import app_cache, AppConfig
     from django.conf import settings
     from django.test import TransactionTestCase, TestCase
 
@@ -165,9 +165,11 @@ def setup(verbosity, test_labels):
             if verbosity >= 2:
                 print("Importing application %s" % module_name)
             # HACK.
-            app_cache._begin_with_app(module_label)
             if module_label not in settings.INSTALLED_APPS:
                 settings.INSTALLED_APPS.append(module_label)
+            app_config = AppConfig.create(module_label)
+            app_config.import_models(app_cache.all_models[app_config.label])
+            app_cache.app_configs[app_config.label] = app_config
 
     return state
 

+ 12 - 14
tests/template_tests/test_loaders.py

@@ -20,12 +20,10 @@ except ImportError:
     pkg_resources = None
 
 
-from django.apps import app_cache
 from django.template import TemplateDoesNotExist, Context
 from django.template.loaders.eggs import Loader as EggLoader
 from django.template import loader
-from django.test import TestCase
-from django.test.utils import override_settings
+from django.test import TestCase, override_settings
 from django.utils import six
 from django.utils._os import upath
 from django.utils.six import StringIO
@@ -78,25 +76,25 @@ class EggLoaderTest(TestCase):
             os.path.normcase('templates/x.txt'): StringIO("x"),
         })
 
+    @override_settings(INSTALLED_APPS=['egg_empty'])
     def test_empty(self):
         "Loading any template on an empty egg should fail"
-        with app_cache._with_app('egg_empty'):
-            egg_loader = EggLoader()
-            self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html")
+        egg_loader = EggLoader()
+        self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html")
 
+    @override_settings(INSTALLED_APPS=['egg_1'])
     def test_non_existing(self):
         "Template loading fails if the template is not in the egg"
-        with app_cache._with_app('egg_1'):
-            egg_loader = EggLoader()
-            self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html")
+        egg_loader = EggLoader()
+        self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html")
 
+    @override_settings(INSTALLED_APPS=['egg_1'])
     def test_existing(self):
         "A template can be loaded from an egg"
-        with app_cache._with_app('egg_1'):
-            egg_loader = EggLoader()
-            contents, template_name = egg_loader.load_template_source("y.html")
-            self.assertEqual(contents, "y")
-            self.assertEqual(template_name, "egg:egg_1:templates/y.html")
+        egg_loader = EggLoader()
+        contents, template_name = egg_loader.load_template_source("y.html")
+        self.assertEqual(contents, "y")
+        self.assertEqual(template_name, "egg:egg_1:templates/y.html")
 
     def test_not_installed(self):
         "Loading an existent template from an egg not included in any app should fail"

+ 3 - 4
tests/template_tests/tests.py

@@ -16,7 +16,6 @@ import unittest
 import warnings
 
 from django import template
-from django.apps import app_cache
 from django.core import urlresolvers
 from django.template import (base as template_base, loader, Context,
     RequestContext, Template, TemplateSyntaxError)
@@ -1879,10 +1878,10 @@ class TemplateTagLoading(TestCase):
         egg_name = '%s/tagsegg.egg' % self.egg_dir
         sys.path.append(egg_name)
         with self.assertRaises(template.TemplateSyntaxError):
-            with app_cache._with_app('tagsegg'):
+            with self.settings(INSTALLED_APPS=['tagsegg']):
                 template.Template(ttext)
         try:
-            with app_cache._with_app('tagsegg'):
+            with self.settings(INSTALLED_APPS=['tagsegg']):
                 template.Template(ttext)
         except template.TemplateSyntaxError as e:
             self.assertTrue('ImportError' in e.args[0])
@@ -1892,7 +1891,7 @@ class TemplateTagLoading(TestCase):
         ttext = "{% load working_egg %}"
         egg_name = '%s/tagsegg.egg' % self.egg_dir
         sys.path.append(egg_name)
-        with app_cache._with_app('tagsegg'):
+        with self.settings(INSTALLED_APPS=['tagsegg']):
             template.Template(ttext)
 
 

+ 4 - 7
tests/utils_tests/test_autoreload.py

@@ -1,7 +1,6 @@
 import os
 
 from django import conf
-from django.apps import app_cache
 from django.contrib import admin
 from django.test import TestCase, override_settings
 from django.utils.autoreload import gen_filenames
@@ -28,6 +27,7 @@ class TestFilenameGenerator(TestCase):
         self.assertIn(os.path.join(LOCALE_PATH, 'nl', 'LC_MESSAGES', 'django.mo'),
                       filenames)
 
+    @override_settings(INSTALLED_APPS=[])
     def test_project_root_locale(self):
         """
         Test that gen_filenames also yields from the current directory (project
@@ -36,22 +36,19 @@ class TestFilenameGenerator(TestCase):
         old_cwd = os.getcwd()
         os.chdir(os.path.dirname(__file__))
         try:
-            # Remove the current app from the app cache to guarantee that the
-            # files will be found thanks to the current working directory.
-            with app_cache._empty():
-                filenames = list(gen_filenames())
+            filenames = list(gen_filenames())
             self.assertIn(
                 os.path.join(LOCALE_PATH, 'nl', 'LC_MESSAGES', 'django.mo'),
                 filenames)
         finally:
             os.chdir(old_cwd)
 
+    @override_settings(INSTALLED_APPS=['django.contrib.admin'])
     def test_app_locales(self):
         """
         Test that gen_filenames also yields from locale dirs in installed apps.
         """
-        with app_cache._empty(), app_cache._with_app('django.contrib.admin'):
-            filenames = list(gen_filenames())
+        filenames = list(gen_filenames())
         self.assertIn(os.path.join(os.path.dirname(admin.__file__), 'locale',
                                    'nl', 'LC_MESSAGES', 'django.mo'),
                       filenames)

+ 2 - 8
tests/utils_tests/test_module_loading.py

@@ -5,9 +5,8 @@ import sys
 import unittest
 from zipimport import zipimporter
 
-from django.apps import app_cache
 from django.core.exceptions import ImproperlyConfigured
-from django.test import SimpleTestCase
+from django.test import SimpleTestCase, modify_settings
 from django.utils import six
 from django.utils.module_loading import autodiscover_modules, import_by_path, module_has_submodule
 from django.utils._os import upath
@@ -135,14 +134,9 @@ class ModuleImportTestCase(unittest.TestCase):
             'Should have more than the calling frame in the traceback.')
 
 
+@modify_settings(INSTALLED_APPS={'append': 'utils_tests.test_module'})
 class AutodiscoverModulesTestCase(SimpleTestCase):
 
-    def setUp(self):
-        self._with_test_module = app_cache._begin_with_app('utils_tests.test_module')
-
-    def tearDown(self):
-        app_cache._end_with_app(self._with_test_module)
-
     def test_autodiscover_modules_found(self):
         autodiscover_modules('good_module')
 

+ 14 - 15
tests/view_tests/tests/test_i18n.py

@@ -4,11 +4,10 @@ import os
 from os import path
 import unittest
 
-from django.apps import app_cache
 from django.conf import settings
 from django.core.urlresolvers import reverse
-from django.test import LiveServerTestCase, TestCase
-from django.test.utils import override_settings
+from django.test import (
+    LiveServerTestCase, TestCase, modify_settings, override_settings)
 from django.utils import six
 from django.utils._os import upath
 from django.utils.translation import override
@@ -110,16 +109,16 @@ class JsI18NTests(TestCase):
             response = self.client.get('/views/jsi18n/')
             self.assertNotContains(response, 'Choisir une heure')
 
+    @modify_settings(INSTALLED_APPS={'append': 'view_tests.app0'})
     def test_nonenglish_default_english_userpref(self):
         """
         Same as above with the difference that there IS an 'en' translation
         available. The Javascript i18n view must return a NON empty language catalog
         with the proper English translations. See #13726 for more details.
         """
-        with app_cache._with_app('view_tests.app0'):
-            with self.settings(LANGUAGE_CODE='fr'), override('en-us'):
-                response = self.client.get('/views/jsi18n_english_translation/')
-                self.assertContains(response, javascript_quote('this app0 string is to be translated'))
+        with self.settings(LANGUAGE_CODE='fr'), override('en-us'):
+            response = self.client.get('/views/jsi18n_english_translation/')
+            self.assertContains(response, javascript_quote('this app0 string is to be translated'))
 
     def testI18NLanguageNonEnglishFallback(self):
         """
@@ -141,6 +140,7 @@ class JsI18NTestsMultiPackage(TestCase):
     Tests for django views in django/views/i18n.py that need to change
     settings.LANGUAGE_CODE and merge JS translation from several packages.
     """
+    @modify_settings(INSTALLED_APPS={'append': ['view_tests.app1', 'view_tests.app2']})
     def testI18NLanguageEnglishDefault(self):
         """
         Check if the JavaScript i18n view returns a complete language catalog
@@ -149,20 +149,19 @@ class JsI18NTestsMultiPackage(TestCase):
         translations of multiple Python packages is requested. See #13388,
         #3594 and #13514 for more details.
         """
-        with app_cache._with_app('view_tests.app1'), app_cache._with_app('view_tests.app2'):
-            with self.settings(LANGUAGE_CODE='en-us'), override('fr'):
-                response = self.client.get('/views/jsi18n_multi_packages1/')
-                self.assertContains(response, javascript_quote('il faut traduire cette chaîne de caractères de app1'))
+        with self.settings(LANGUAGE_CODE='en-us'), override('fr'):
+            response = self.client.get('/views/jsi18n_multi_packages1/')
+            self.assertContains(response, javascript_quote('il faut traduire cette chaîne de caractères de app1'))
 
+    @modify_settings(INSTALLED_APPS={'append': ['view_tests.app3', 'view_tests.app4']})
     def testI18NDifferentNonEnLangs(self):
         """
         Similar to above but with neither default or requested language being
         English.
         """
-        with app_cache._with_app('view_tests.app3'), app_cache._with_app('view_tests.app4'):
-            with self.settings(LANGUAGE_CODE='fr'), override('es-ar'):
-                response = self.client.get('/views/jsi18n_multi_packages2/')
-                self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido'))
+        with self.settings(LANGUAGE_CODE='fr'), override('es-ar'):
+            response = self.client.get('/views/jsi18n_multi_packages2/')
+            self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido'))
 
     def testI18NWithLocalePaths(self):
         extended_locale_paths = settings.LOCALE_PATHS + (