mirror of
https://github.com/django/django.git
synced 2024-11-29 06:03:25 +01:00
Terminated AppCache._populate() with extreme prejudice.
It was called _populate() before I renamed it to populate(). Since it has been superseded by populate_models() there's no reason to keep it. Removed the can_postpone argument of load_app() as it was only used by populate(). It's a private API and there's no replacement. Simplified load_app() accordingly. Then new version behaves exactly like the old one even though it's much shorter.
This commit is contained in:
parent
2b56d69102
commit
86804ab063
@ -18,7 +18,7 @@ class BaseValidator(object):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Before we can introspect models, they need the app cache to be fully
|
# Before we can introspect models, they need the app cache to be fully
|
||||||
# loaded so that inter-relations are set up correctly.
|
# loaded so that inter-relations are set up correctly.
|
||||||
app_cache.populate()
|
app_cache.populate_models()
|
||||||
|
|
||||||
def validate(self, cls, model):
|
def validate(self, cls, model):
|
||||||
for m in dir(self):
|
for m in dir(self):
|
||||||
|
@ -2,17 +2,16 @@
|
|||||||
|
|
||||||
from collections import defaultdict, OrderedDict
|
from collections import defaultdict, OrderedDict
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from importlib import import_module
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.module_loading import import_lock, module_has_submodule
|
from django.utils.module_loading import import_lock
|
||||||
from django.utils._os import upath
|
from django.utils._os import upath
|
||||||
|
|
||||||
from .base import AppConfig, MODELS_MODULE_NAME
|
from .base import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class UnavailableApp(Exception):
|
class UnavailableApp(Exception):
|
||||||
@ -51,15 +50,11 @@ class AppCache(object):
|
|||||||
# Used by TransactionTestCase.available_apps for performance reasons.
|
# Used by TransactionTestCase.available_apps for performance reasons.
|
||||||
self.available_apps = None
|
self.available_apps = None
|
||||||
|
|
||||||
# Internal flags used when populating the cache.
|
# Internal flags used when populating the master cache.
|
||||||
self._apps_loaded = False
|
self._apps_loaded = not self.master
|
||||||
self._models_loaded = False
|
self._models_loaded = not self.master
|
||||||
|
|
||||||
# -- Everything below here is only used when populating the cache --
|
# Cache for get_models.
|
||||||
self.loaded = False
|
|
||||||
self.handled = set()
|
|
||||||
self.postponed = []
|
|
||||||
self.nesting_level = 0
|
|
||||||
self._get_models_cache = {}
|
self._get_models_cache = {}
|
||||||
|
|
||||||
def populate_apps(self):
|
def populate_apps(self):
|
||||||
@ -138,71 +133,15 @@ class AppCache(object):
|
|||||||
|
|
||||||
self._models_loaded = True
|
self._models_loaded = True
|
||||||
|
|
||||||
def populate(self):
|
def load_app(self, app_name):
|
||||||
"""
|
|
||||||
Fill in all the cache information. This method is threadsafe, in the
|
|
||||||
sense that every caller will see the same state upon return, and if the
|
|
||||||
cache is already initialised, it does no work.
|
|
||||||
"""
|
|
||||||
if self.loaded:
|
|
||||||
return
|
|
||||||
if not self.master:
|
|
||||||
self.loaded = True
|
|
||||||
return
|
|
||||||
# Note that we want to use the import lock here - the app loading is
|
|
||||||
# in many cases initiated implicitly by importing, and thus it is
|
|
||||||
# possible to end up in deadlock when one thread initiates loading
|
|
||||||
# without holding the importer lock and another thread then tries to
|
|
||||||
# import something which also launches the app loading. For details of
|
|
||||||
# this situation see #18251.
|
|
||||||
with import_lock():
|
|
||||||
if self.loaded:
|
|
||||||
return
|
|
||||||
for app_name in settings.INSTALLED_APPS:
|
|
||||||
if app_name in self.handled:
|
|
||||||
continue
|
|
||||||
self.load_app(app_name, can_postpone=True)
|
|
||||||
if not self.nesting_level:
|
|
||||||
for app_name in self.postponed:
|
|
||||||
self.load_app(app_name)
|
|
||||||
self.loaded = True
|
|
||||||
|
|
||||||
def load_app(self, app_name, can_postpone=False):
|
|
||||||
"""
|
"""
|
||||||
Loads the app with the provided fully qualified name, and returns the
|
Loads the app with the provided fully qualified name, and returns the
|
||||||
model module.
|
model module.
|
||||||
"""
|
"""
|
||||||
app_module = import_module(app_name)
|
|
||||||
self.handled.add(app_name)
|
|
||||||
self.nesting_level += 1
|
|
||||||
try:
|
|
||||||
models_module = import_module('%s.%s' % (app_name, MODELS_MODULE_NAME))
|
|
||||||
except ImportError:
|
|
||||||
# If the app doesn't have a models module, we can just swallow the
|
|
||||||
# ImportError and return no models for this app.
|
|
||||||
if not module_has_submodule(app_module, MODELS_MODULE_NAME):
|
|
||||||
models_module = None
|
|
||||||
# But if the app does have a models module, we need to figure out
|
|
||||||
# whether to suppress or propagate the error. If can_postpone is
|
|
||||||
# True then it may be that the package is still being imported by
|
|
||||||
# Python and the models module isn't available yet. So we add the
|
|
||||||
# app to the postponed list and we'll try it again after all the
|
|
||||||
# recursion has finished (in populate). If can_postpone is False
|
|
||||||
# then it's time to raise the ImportError.
|
|
||||||
else:
|
|
||||||
if can_postpone:
|
|
||||||
self.postponed.append(app_name)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
self.nesting_level -= 1
|
|
||||||
|
|
||||||
app_config = AppConfig(app_name)
|
app_config = AppConfig(app_name)
|
||||||
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
|
||||||
|
return app_config.models_module
|
||||||
return models_module
|
|
||||||
|
|
||||||
def app_cache_ready(self):
|
def app_cache_ready(self):
|
||||||
"""
|
"""
|
||||||
@ -211,7 +150,7 @@ class AppCache(object):
|
|||||||
Useful for code that wants to cache the results of get_models() for
|
Useful for code that wants to cache the results of get_models() for
|
||||||
themselves once it is safe to do so.
|
themselves once it is safe to do so.
|
||||||
"""
|
"""
|
||||||
return self.loaded
|
return self._models_loaded # implies self._apps_loaded.
|
||||||
|
|
||||||
def get_app_configs(self, only_with_models_module=False):
|
def get_app_configs(self, only_with_models_module=False):
|
||||||
"""
|
"""
|
||||||
@ -220,7 +159,7 @@ class AppCache(object):
|
|||||||
If only_with_models_module in True (non-default), only applications
|
If only_with_models_module in True (non-default), only applications
|
||||||
containing a models module are considered.
|
containing a models module are considered.
|
||||||
"""
|
"""
|
||||||
self.populate()
|
self.populate_models()
|
||||||
for app_config in self.app_configs.values():
|
for app_config in self.app_configs.values():
|
||||||
if only_with_models_module and app_config.models_module is None:
|
if only_with_models_module and app_config.models_module is None:
|
||||||
continue
|
continue
|
||||||
@ -240,7 +179,7 @@ class AppCache(object):
|
|||||||
If only_with_models_module in True (non-default), only applications
|
If only_with_models_module in True (non-default), only applications
|
||||||
containing a models module are considered.
|
containing a models module are considered.
|
||||||
"""
|
"""
|
||||||
self.populate()
|
self.populate_models()
|
||||||
app_config = self.app_configs.get(app_label)
|
app_config = self.app_configs.get(app_label)
|
||||||
if app_config is None:
|
if app_config is None:
|
||||||
raise LookupError("No installed app with label %r." % app_label)
|
raise LookupError("No installed app with label %r." % app_label)
|
||||||
@ -288,7 +227,7 @@ class AppCache(object):
|
|||||||
return model_list
|
return model_list
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
self.populate()
|
self.populate_models()
|
||||||
if app_mod:
|
if app_mod:
|
||||||
app_label = app_mod.__name__.split('.')[-2]
|
app_label = app_mod.__name__.split('.')[-2]
|
||||||
if only_installed:
|
if only_installed:
|
||||||
@ -331,7 +270,7 @@ class AppCache(object):
|
|||||||
"""
|
"""
|
||||||
if not self.master:
|
if not self.master:
|
||||||
only_installed = False
|
only_installed = False
|
||||||
self.populate()
|
self.populate_models()
|
||||||
if only_installed:
|
if only_installed:
|
||||||
app_config = self.app_configs.get(app_label)
|
app_config = self.app_configs.get(app_label)
|
||||||
if app_config is None:
|
if app_config is None:
|
||||||
@ -496,7 +435,7 @@ class AppCache(object):
|
|||||||
"[a.path for a in get_app_configs()] supersedes get_app_paths().",
|
"[a.path for a in get_app_configs()] supersedes get_app_paths().",
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
PendingDeprecationWarning, stacklevel=2)
|
||||||
|
|
||||||
self.populate()
|
self.populate_models()
|
||||||
|
|
||||||
app_paths = []
|
app_paths = []
|
||||||
for app in self.get_apps():
|
for app in self.get_apps():
|
||||||
|
@ -139,7 +139,7 @@ class Deserializer(six.Iterator):
|
|||||||
self.stream = stream_or_string
|
self.stream = stream_or_string
|
||||||
# Make sure the app cache is loaded before deserialization starts
|
# Make sure the app cache is loaded before deserialization starts
|
||||||
# (otherwise subclass calls to get_model() and friends might fail...)
|
# (otherwise subclass calls to get_model() and friends might fail...)
|
||||||
app_cache.populate()
|
app_cache.populate_models()
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
@ -88,7 +88,7 @@ def Deserializer(object_list, **options):
|
|||||||
db = options.pop('using', DEFAULT_DB_ALIAS)
|
db = options.pop('using', DEFAULT_DB_ALIAS)
|
||||||
ignore = options.pop('ignorenonexistent', False)
|
ignore = options.pop('ignorenonexistent', False)
|
||||||
|
|
||||||
app_cache.populate()
|
app_cache.populate_models()
|
||||||
|
|
||||||
for d in object_list:
|
for d in object_list:
|
||||||
# Look up the model and starting build a dict of data for it.
|
# Look up the model and starting build a dict of data for it.
|
||||||
|
@ -6,7 +6,7 @@ from functools import update_wrapper
|
|||||||
from django.utils.six.moves import zip
|
from django.utils.six.moves import zip
|
||||||
|
|
||||||
from django.core.apps import app_cache
|
from django.core.apps import app_cache
|
||||||
from django.core.apps.cache import MODELS_MODULE_NAME
|
from django.core.apps.base import MODELS_MODULE_NAME
|
||||||
import django.db.models.manager # NOQA: Imported to register signal handler.
|
import django.db.models.manager # NOQA: Imported to register signal handler.
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import (ObjectDoesNotExist,
|
from django.core.exceptions import (ObjectDoesNotExist,
|
||||||
|
@ -30,6 +30,6 @@ def get_app_errors():
|
|||||||
try:
|
try:
|
||||||
return app_cache.app_errors
|
return app_cache.app_errors
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
app_cache.populate()
|
app_cache.populate_models()
|
||||||
app_cache.app_errors = {}
|
app_cache.app_errors = {}
|
||||||
return app_cache.app_errors
|
return app_cache.app_errors
|
||||||
|
@ -93,7 +93,7 @@ class Options(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def app_config(self):
|
def app_config(self):
|
||||||
# Don't go through get_app_config to avoid triggering populate().
|
# Don't go through get_app_config to avoid triggering imports.
|
||||||
return self.app_cache.app_configs.get(self.app_label)
|
return self.app_cache.app_configs.get(self.app_label)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -77,8 +77,9 @@ class EggLoadingTest(TestCase):
|
|||||||
error. Refs #17667.
|
error. Refs #17667.
|
||||||
"""
|
"""
|
||||||
app_cache = AppCache()
|
app_cache = AppCache()
|
||||||
# Pretend we're the master app cache to test populate().
|
# Pretend we're the master app cache to test the population process.
|
||||||
app_cache.master = True
|
app_cache._apps_loaded = False
|
||||||
|
app_cache._models_loaded = False
|
||||||
with override_settings(INSTALLED_APPS=('notexists',)):
|
with override_settings(INSTALLED_APPS=('notexists',)):
|
||||||
with self.assertRaises(ImportError):
|
with self.assertRaises(ImportError):
|
||||||
app_cache.get_model('notexists', 'nomodel')
|
app_cache.get_model('notexists', 'nomodel')
|
||||||
|
@ -128,7 +128,7 @@ def setup(verbosity, test_labels):
|
|||||||
# Load all the ALWAYS_INSTALLED_APPS.
|
# Load all the ALWAYS_INSTALLED_APPS.
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.filterwarnings('ignore', 'django.contrib.comments is deprecated and will be removed before Django 1.8.', DeprecationWarning)
|
warnings.filterwarnings('ignore', 'django.contrib.comments is deprecated and will be removed before Django 1.8.', DeprecationWarning)
|
||||||
app_cache.populate()
|
app_cache.populate_models()
|
||||||
|
|
||||||
# Load all the test model apps.
|
# Load all the test model apps.
|
||||||
test_modules = get_test_modules()
|
test_modules = get_test_modules()
|
||||||
|
Loading…
Reference in New Issue
Block a user