Skip to content

Commit

Permalink
Fixed #27176 -- Raised an exception for reentrant calls to apps.popul…
Browse files Browse the repository at this point in the history
…ate().

Thanks to Aymeric Augustin, Harry Percival, and Tim Graham.
  • Loading branch information
francoisfreitag authored and timgraham committed Feb 25, 2017
1 parent 12745d8 commit fba4f83
Showing 1 changed file with 9 additions and 5 deletions.
14 changes: 9 additions & 5 deletions django/apps/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def __init__(self, installed_apps=()):
self.apps_ready = self.models_ready = self.ready = False

# Lock for thread-safe population.
self._lock = threading.Lock()
self._lock = threading.RLock()
self.loading = False

# Maps ("app_label", "modelname") tuples to lists of functions to be
# called when the corresponding model is ready. Used by this class's
Expand Down Expand Up @@ -72,10 +73,13 @@ def populate(self, installed_apps=None):
if self.ready:
return

# app_config should be pristine, otherwise the code below won't
# guarantee that the order matches the order in INSTALLED_APPS.
if self.app_configs:
# An RLock prevents other threads from entering this section. The
# compare and set operation below is atomic.
if self.loading:
# Prevent reentrant calls to avoid running AppConfig.ready()
# methods twice.
raise RuntimeError("populate() isn't reentrant")
self.loading = True

# Phase 1: initialize app configs and import app modules.
for entry in installed_apps:
Expand Down Expand Up @@ -345,7 +349,7 @@ def set_installed_apps(self, installed):
raise AppRegistryNotReady("App registry isn't ready yet.")
self.stored_app_configs.append(self.app_configs)
self.app_configs = OrderedDict()
self.apps_ready = self.models_ready = self.ready = False
self.apps_ready = self.models_ready = self.loading = self.ready = False
self.clear_cache()
self.populate(installed)

Expand Down

0 comments on commit fba4f83

Please sign in to comment.