Improved set_available_apps() in several ways.

- Tested consistency the current app_configs instead of INSTALLED_APPS.
- Considered applications added with _with_app as available.
- Added docstrings.
This commit is contained in:
Aymeric Augustin 2013-12-20 10:39:12 +01:00
parent 2239081ff1
commit 16aae35ca8
2 changed files with 19 additions and 5 deletions

View File

@ -320,14 +320,27 @@ class AppCache(object):
return self.all_models[app_label].get(model_name.lower()) return self.all_models[app_label].get(model_name.lower())
def set_available_apps(self, available): def set_available_apps(self, available):
"""
Restricts the set of installed apps used by get_app_config[s].
available must be an iterable of application names.
Primarily used for performance optimization in TransactionTestCase.
"""
if self.available_apps is not None:
raise RuntimeError("set_available_apps() may be called only once "
"in a row; make sure it's paired with unset_available_apps()")
available = set(available) available = set(available)
installed = set(settings.INSTALLED_APPS) installed = set(app_config.name for app_config in self.get_app_configs())
if not available.issubset(installed): if not available.issubset(installed):
raise ValueError("Available apps isn't a subset of installed " raise ValueError("Available apps isn't a subset of installed "
"apps, extra apps: %s" % ", ".join(available - installed)) "apps, extra apps: %s" % ", ".join(available - installed))
self.available_apps = available self.available_apps = available
def unset_available_apps(self): def unset_available_apps(self):
"""
Cancels a previous call to set_available_apps().
"""
self.available_apps = None self.available_apps = None
### DANGEROUS METHODS ### (only used to preserve existing tests) ### DANGEROUS METHODS ### (only used to preserve existing tests)
@ -340,11 +353,15 @@ class AppCache(object):
else: else:
app_config.import_models(self.all_models[app_config.label]) app_config.import_models(self.all_models[app_config.label])
self.app_configs[app_config.label] = app_config self.app_configs[app_config.label] = app_config
if self.available_apps is not None:
self.available_apps.add(app_config.name)
return app_config return app_config
def _end_with_app(self, app_config): def _end_with_app(self, app_config):
if app_config is not None: if app_config is not None:
del self.app_configs[app_config.label] del self.app_configs[app_config.label]
if self.available_apps is not None:
self.available_apps.discard(app_config.name)
@contextmanager @contextmanager
def _with_app(self, app_name): def _with_app(self, app_name):

View File

@ -6,22 +6,19 @@ import sys
from django.core.apps import app_cache from django.core.apps import app_cache
from django.core.management import call_command from django.core.management import call_command
from django.test import TestCase, TransactionTestCase from django.test import TestCase, TransactionTestCase
from django.test.utils import override_settings
from django.utils._os import upath from django.utils._os import upath
from .models import (ConcreteModel, ConcreteModelSubclass, from .models import (ConcreteModel, ConcreteModelSubclass,
ConcreteModelSubclassProxy) ConcreteModelSubclassProxy)
# Required for available_apps.
@override_settings(INSTALLED_APPS=['app1', 'app2'])
class ProxyModelInheritanceTests(TransactionTestCase): class ProxyModelInheritanceTests(TransactionTestCase):
""" """
Proxy model inheritance across apps can result in migrate not creating the table Proxy model inheritance across apps can result in migrate not creating the table
for the proxied model (as described in #12286). This test creates two dummy for the proxied model (as described in #12286). This test creates two dummy
apps and calls migrate, then verifies that the table has been created. apps and calls migrate, then verifies that the table has been created.
""" """
available_apps = ['app1', 'app2'] available_apps = []
def setUp(self): def setUp(self):
self.old_sys_path = sys.path[:] self.old_sys_path = sys.path[:]