Code

Ticket #3591: app_labels.10.diff

File app_labels.10.diff, 31.7 KB (added by Vinay Sajip <vinay_sajip@…>, 6 years ago)

Updated to apply cleanly against r8965 (post 1.0).

Line 
1Index: django/test/simple.py
2===================================================================
3--- django/test/simple.py       (revision 8965)
4+++ django/test/simple.py       (working copy)
5@@ -63,7 +63,7 @@
6             suite.addTest(test_module.suite())
7         else:
8             suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
9-            try:           
10+            try:
11                 suite.addTest(doctest.DocTestSuite(test_module,
12                                                    checker=doctestOutputChecker,
13                                                    runner=DocTestRunner))
14@@ -129,10 +129,14 @@
15                 suite.addTest(build_test(label))
16             else:
17                 app = get_app(label)
18-                suite.addTest(build_suite(app))
19+                mod = app.models_module
20+                if mod:
21+                  suite.addTest(build_suite(mod))
22     else:
23         for app in get_apps():
24-            suite.addTest(build_suite(app))
25+            mod = app.models_module
26+            if mod:
27+                suite.addTest(build_suite(mod))
28     
29     for test in extra_tests:
30         suite.addTest(test)
31Index: django/test/client.py
32===================================================================
33--- django/test/client.py       (revision 8965)
34+++ django/test/client.py       (working copy)
35@@ -6,7 +6,7 @@
36 except ImportError:
37     from StringIO import StringIO
38 
39-from django.conf import settings
40+from django.conf import settings, get_installed_app_paths
41 from django.contrib.auth import authenticate, login
42 from django.core.handlers.base import BaseHandler
43 from django.core.handlers.wsgi import WSGIRequest
44@@ -169,7 +169,7 @@
45         """
46         Obtains the current session variables.
47         """
48-        if 'django.contrib.sessions' in settings.INSTALLED_APPS:
49+        if 'django.contrib.sessions' in get_installed_app_paths():
50             engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
51             cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
52             if cookie:
53@@ -294,7 +294,7 @@
54         """
55         user = authenticate(**credentials)
56         if user and user.is_active \
57-                and 'django.contrib.sessions' in settings.INSTALLED_APPS:
58+                and 'django.contrib.sessions' in get_installed_app_paths():
59             engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
60 
61             # Create a fake request to store login details.
62Index: django/conf/__init__.py
63===================================================================
64--- django/conf/__init__.py     (revision 8965)
65+++ django/conf/__init__.py     (working copy)
66@@ -108,15 +108,15 @@
67         # of all those apps.
68         new_installed_apps = []
69         for app in self.INSTALLED_APPS:
70-            if app.endswith('.*'):
71+            if not isinstance(app, basestring) or not app.endswith('.*'):
72+                new_installed_apps.append(app)
73+            else:
74                 appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__)
75                 app_subdirs = os.listdir(appdir)
76                 app_subdirs.sort()
77                 for d in app_subdirs:
78                     if d.isalpha() and os.path.isdir(os.path.join(appdir, d)):
79                         new_installed_apps.append('%s.%s' % (app[:-2], d))
80-            else:
81-                new_installed_apps.append(app)
82         self.INSTALLED_APPS = new_installed_apps
83 
84         if hasattr(time, 'tzset'):
85@@ -151,3 +151,25 @@
86 
87 settings = LazySettings()
88 
89+class app(object):
90+    """Configuration directive for specifying an app."""
91+    def __init__(self, path, app_label=None, verbose_name=None):
92+        self.path = path
93+        # if name isn't specified, get the last part of the Python dotted path
94+        self.label = app_label or path.split('.')[-1]
95+        self.verbose_name = verbose_name or self.label
96+        self.app_module = None    # will be filled in by loading.py
97+        self.models_module = None # will be filled in by loading.py
98+
99+    def __repr__(self):
100+        return "<app: %s>" % self.path
101+
102+def get_installed_app_paths():
103+    "Return the paths of all entries in settings.INSTALLED_APPS."
104+    rv = []
105+    for a in settings.INSTALLED_APPS:
106+        if isinstance(a, basestring):
107+            rv.append(a)
108+        else:
109+            rv.append(a.path)
110+    return rv
111Index: django/db/models/base.py
112===================================================================
113--- django/db/models/base.py    (revision 8965)
114+++ django/db/models/base.py    (working copy)
115@@ -16,7 +16,7 @@
116 from django.db.models.options import Options
117 from django.db import connection, transaction, DatabaseError
118 from django.db.models import signals
119-from django.db.models.loading import register_models, get_model
120+from django.db.models.loading import register_models, get_model, get_app_label
121 from django.utils.functional import curry
122 from django.utils.encoding import smart_str, force_unicode, smart_unicode
123 from django.conf import settings
124@@ -69,6 +69,9 @@
125 
126         if getattr(new_class, '_default_manager', None):
127             new_class._default_manager = None
128+        if getattr(new_class._meta, 'app_label', None) is None:
129+            # Figure out the app_label.
130+            new_class._meta.app_label = get_app_label(new_class)
131 
132         # Bail out early if we have already created this class.
133         m = get_model(new_class._meta.app_label, name, False)
134Index: django/db/models/options.py
135===================================================================
136--- django/db/models/options.py (revision 8965)
137+++ django/db/models/options.py (working copy)
138@@ -5,7 +5,7 @@
139 except NameError:
140     from sets import Set as set     # Python 2.3 fallback
141 
142-from django.conf import settings
143+from django.conf import settings, get_installed_app_paths
144 from django.db.models.related import RelatedObject
145 from django.db.models.fields.related import ManyToManyRel
146 from django.db.models.fields import AutoField, FieldDoesNotExist
147@@ -54,7 +54,7 @@
148         from django.db.backends.util import truncate_name
149 
150         cls._meta = self
151-        self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
152+        self.installed = re.sub('\.models$', '', cls.__module__) in get_installed_app_paths()
153         # First, construct the default values for these options.
154         self.object_name = cls.__name__
155         self.module_name = self.object_name.lower()
156Index: django/db/models/loading.py
157===================================================================
158--- django/db/models/loading.py (revision 8965)
159+++ django/db/models/loading.py (working copy)
160@@ -1,15 +1,15 @@
161 "Utilities for loading models and the modules that contain them."
162 
163-from django.conf import settings
164+from django.conf import settings, app
165 from django.core.exceptions import ImproperlyConfigured
166 from django.utils.datastructures import SortedDict
167 
168 import sys
169-import os
170+import os, os.path
171 import threading
172 
173 __all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models',
174-        'load_app', 'app_cache_ready')
175+        'load_app', 'app_cache_ready', 'find_app')
176 
177 class AppCache(object):
178     """
179@@ -28,6 +28,16 @@
180         # Mapping of app_labels to errors raised when trying to import the app.
181         app_errors = {},
182 
183+
184+        # Mapping of app_labels to app instances.
185+        app_map = {},
186+
187+        # Mapping of app module names to app instances.
188+        mod_map = {},
189+
190+        # List of app instances.
191+        app_instances = [],
192+
193         # -- Everything below here is only used when populating the cache --
194         loaded = False,
195         handled = {},
196@@ -51,13 +61,42 @@
197         try:
198             if self.loaded:
199                 return
200-            for app_name in settings.INSTALLED_APPS:
201+            # We first loop through, setting up the app instances and
202+            # the relevant maps so that we can find the instances by app_label
203+            # or app module name. These need to be ready because we need to be
204+            # able to get the app_label e.g. for applying to model classes.
205+            # If a model class is loaded indirectly without being in an
206+            # installed app, the app_label used will be what it is now - the
207+            # last part of the app module name.
208+            # Note that app_map and mod_map will contain entries even
209+            # when an app cannot be loaded by load_app.
210+            for app_entry in settings.INSTALLED_APPS:
211+                if isinstance(app_entry, basestring):
212+                    the_app = app(app_entry)
213+                else:
214+                    the_app = app_entry
215+                self.app_map[the_app.label] = the_app
216+                self.mod_map[the_app.path] = the_app
217+
218+            for app_entry in settings.INSTALLED_APPS:
219+                if isinstance(app_entry, basestring):
220+                    the_app = self.mod_map[app_entry]
221+                else:
222+                    the_app = app_entry
223+                app_name = the_app.path
224                 if app_name in self.handled:
225                     continue
226-                self.load_app(app_name, True)
227+                try:
228+                    self.load_app(app_name, True)
229+                    self.app_instances.append(the_app)
230+                except Exception, e:
231+                    # Problem importing the app
232+                    self.app_errors[app_name] = e
233             if not self.nesting_level:
234                 for app_name in self.postponed:
235+                    the_app = self.mod_map[app_name]
236                     self.load_app(app_name)
237+                    self.app_instances.append(the_app)                   
238                 self.loaded = True
239         finally:
240             self.write_lock.release()
241@@ -71,6 +110,16 @@
242         self.nesting_level += 1
243         mod = __import__(app_name, {}, {}, ['models'])
244         self.nesting_level -= 1
245+        if app_name in self.mod_map:
246+            the_app = self.mod_map[app_name]
247+        else:
248+            # An app can be loaded by load_app even before get_apps is
249+            # called. In this case, we just make a new app and add it to the maps.
250+            the_app = app(app_name)
251+            self.app_map[the_app.label] = the_app
252+            self.mod_map[app_name] = the_app
253+            self.app_instances.append(the_app)
254+        the_app.app_module = mod
255         if not hasattr(mod, 'models'):
256             if can_postpone:
257                 # Either the app has no models, or the package is still being
258@@ -78,10 +127,13 @@
259                 # We will check again once all the recursion has finished (in
260                 # populate).
261                 self.postponed.append(app_name)
262-            return None
263-        if mod.models not in self.app_store:
264-            self.app_store[mod.models] = len(self.app_store)
265-        return mod.models
266+            rv = None
267+        else:
268+            rv = mod.models
269+            if rv not in self.app_store:
270+                self.app_store[rv] = len(self.app_store)
271+        the_app.models_module = rv
272+        return rv
273 
274     def app_cache_ready(self):
275         """
276@@ -101,45 +153,61 @@
277         # list page, for example.
278         apps = [(v, k) for k, v in self.app_store.items()]
279         apps.sort()
280-        return [elt[1] for elt in apps]
281+        #return [elt[1] for elt in apps]
282+        return self.app_instances
283 
284+    def get_app_label(self, model_class):
285+        "Returns the app label to be used for a model class."
286+        key = model_class.__module__
287+        i = key.rfind('.')
288+        assert i > 0, "Model class must be defined in a package sub-module"
289+        key = key[:i]
290+        if key in self.mod_map:
291+            rv = self.mod_map[key].label
292+        else:
293+            i = key.rfind('.')
294+            if i < 0:
295+                rv = key
296+            else:
297+                rv = key[i + 1:]
298+        return rv
299+   
300+    def find_app(self, app_path):
301+        "Find an app instance, given the application path."
302+        self._populate()
303+        return self.mod_map[app_path]
304+
305     def get_app(self, app_label, emptyOK=False):
306         """
307-        Returns the module containing the models for the given app_label. If
308+        Returns the app instance for the given app_label. If
309         the app has no models in it and 'emptyOK' is True, returns None.
310         """
311         self._populate()
312-        self.write_lock.acquire()
313-        try:
314-            for app_name in settings.INSTALLED_APPS:
315-                if app_label == app_name.split('.')[-1]:
316-                    mod = self.load_app(app_name, False)
317-                    if mod is None:
318-                        if emptyOK:
319-                            return None
320-                    else:
321-                        return mod
322-            raise ImproperlyConfigured, "App with label %s could not be found" % app_label
323-        finally:
324-            self.write_lock.release()
325+        if app_label not in self.app_map:
326+            rv = None
327+        else:
328+            rv = self.app_map[app_label]
329+        if emptyOK or rv is not None:
330+            return rv
331+        raise ImproperlyConfigured, "App with label %s could not be found" % app_label
332 
333     def get_app_errors(self):
334         "Returns the map of known problems with the INSTALLED_APPS."
335         self._populate()
336         return self.app_errors
337 
338-    def get_models(self, app_mod=None):
339+    def get_models(self, the_app=None):
340         """
341-        Given a module containing models, returns a list of the models.
342+        Given an app instance, returns a list of its models.
343         Otherwise returns a list of all installed models.
344         """
345         self._populate()
346-        if app_mod:
347-            return self.app_models.get(app_mod.__name__.split('.')[-2], SortedDict()).values()
348+        if the_app:
349+            return self.app_models.get(the_app.label, SortedDict()).values()
350         else:
351             model_list = []
352-            for app_entry in self.app_models.itervalues():
353-                model_list.extend(app_entry.values())
354+            for the_app in self.app_instances:
355+                model_list.extend(get_models(the_app))
356             return model_list
357 
358     def get_model(self, app_label, model_name, seed_cache=True):
359@@ -187,3 +255,5 @@
360 register_models = cache.register_models
361 load_app = cache.load_app
362 app_cache_ready = cache.app_cache_ready
363+find_app = cache.find_app
364+get_app_label = cache.get_app_label
365Index: django/db/models/__init__.py
366===================================================================
367--- django/db/models/__init__.py        (revision 8965)
368+++ django/db/models/__init__.py        (working copy)
369@@ -1,7 +1,7 @@
370 from django.conf import settings
371 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
372 from django.db import connection
373-from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models
374+from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models, find_app
375 from django.db.models.query import Q
376 from django.db.models.manager import Manager
377 from django.db.models.base import Model
378Index: django/db/backends/oracle/base.py
379===================================================================
380--- django/db/backends/oracle/base.py   (revision 8965)
381+++ django/db/backends/oracle/base.py   (working copy)
382@@ -361,8 +361,8 @@
383             return Database.Cursor.execute(self, query, self._param_generator(params))
384         except DatabaseError, e:
385             # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
386-            if e.args[0].code == 1400 and not isinstance(e, IntegrityError):
387-                e = IntegrityError(e.args[0])
388+            if e.message.code == 1400 and type(e) != IntegrityError:
389+                e = IntegrityError(e.message)
390             raise e
391 
392     def executemany(self, query, params=None):
393@@ -384,8 +384,8 @@
394             return Database.Cursor.executemany(self, query, [self._param_generator(p) for p in formatted])
395         except DatabaseError, e:
396             # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
397-            if e.args[0].code == 1400 and not isinstance(e, IntegrityError):
398-                e = IntegrityError(e.args[0])
399+            if e.message.code == 1400 and type(e) != IntegrityError:
400+                e = IntegrityError(e.message)
401             raise e
402 
403     def fetchone(self):
404Index: django/core/management/commands/loaddata.py
405===================================================================
406--- django/core/management/commands/loaddata.py (revision 8965)
407+++ django/core/management/commands/loaddata.py (working copy)
408@@ -57,7 +57,7 @@
409             transaction.enter_transaction_management()
410             transaction.managed(True)
411 
412-        app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()]
413+        app_fixtures = [os.path.join(os.path.dirname(app.app_module.__file__), 'fixtures') for app in get_apps() if app.app_module]
414         for fixture_label in fixture_labels:
415             parts = fixture_label.split('.')
416             if len(parts) == 1:
417Index: django/core/management/commands/flush.py
418===================================================================
419--- django/core/management/commands/flush.py    (revision 8965)
420+++ django/core/management/commands/flush.py    (working copy)
421@@ -1,3 +1,4 @@
422+from django.conf import get_installed_app_paths
423 from django.core.management.base import NoArgsCommand, CommandError
424 from django.core.management.color import no_style
425 from optparse import make_option
426@@ -24,7 +25,7 @@
427 
428         # Import the 'management' module within each installed app, to register
429         # dispatcher events.
430-        for app_name in settings.INSTALLED_APPS:
431+        for app_name in get_installed_app_paths():
432             try:
433                 __import__(app_name + '.management', {}, {}, [''])
434             except ImportError:
435Index: django/core/management/commands/syncdb.py
436===================================================================
437--- django/core/management/commands/syncdb.py   (revision 8965)
438+++ django/core/management/commands/syncdb.py   (working copy)
439@@ -1,3 +1,4 @@
440+from django.conf import get_installed_app_paths
441 from django.core.management.base import NoArgsCommand
442 from django.core.management.color import no_style
443 from optparse import make_option
444@@ -31,7 +32,7 @@
445 
446         # Import the 'management' module within each installed app, to register
447         # dispatcher events.
448-        for app_name in settings.INSTALLED_APPS:
449+        for app_name in get_installed_app_paths():
450             try:
451                 __import__(app_name + '.management', {}, {}, [''])
452             except ImportError, exc:
453@@ -58,7 +59,7 @@
454 
455         # Create the tables for each model
456         for app in models.get_apps():
457-            app_name = app.__name__.split('.')[-2]
458+            app_name = app.label
459             model_list = models.get_models(app)
460             for model in model_list:
461                 # Create the model's database table, if it doesn't already exist.
462@@ -83,7 +84,7 @@
463         # Create the m2m tables. This must be done after all tables have been created
464         # to ensure that all referred tables will exist.
465         for app in models.get_apps():
466-            app_name = app.__name__.split('.')[-2]
467+            app_name = app.label
468             model_list = models.get_models(app)
469             for model in model_list:
470                 if model in created_models:
471@@ -106,7 +107,7 @@
472         # Install custom SQL for the app (but only if this
473         # is a model we've just created)
474         for app in models.get_apps():
475-            app_name = app.__name__.split('.')[-2]
476+            app_name = app.label
477             for model in models.get_models(app):
478                 if model in created_models:
479                     custom_sql = custom_sql_for_model(model, self.style)
480@@ -130,7 +131,7 @@
481                             print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name)
482         # Install SQL indicies for all newly created models
483         for app in models.get_apps():
484-            app_name = app.__name__.split('.')[-2]
485+            app_name = app.label
486             for model in models.get_models(app):
487                 if model in created_models:
488                     index_sql = connection.creation.sql_indexes_for_model(model, self.style)
489Index: django/core/management/__init__.py
490===================================================================
491--- django/core/management/__init__.py  (revision 8965)
492+++ django/core/management/__init__.py  (working copy)
493@@ -96,8 +96,8 @@
494 
495         # Find the installed apps
496         try:
497-            from django.conf import settings
498-            apps = settings.INSTALLED_APPS
499+            from django.conf import settings, get_installed_app_paths
500+            apps = get_installed_app_paths()
501         except (AttributeError, EnvironmentError, ImportError):
502             apps = []
503 
504Index: django/core/management/sql.py
505===================================================================
506--- django/core/management/sql.py       (revision 8965)
507+++ django/core/management/sql.py       (working copy)
508@@ -137,7 +137,7 @@
509     output = []
510 
511     app_models = get_models(app)
512-    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
513+    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.app_module.__file__), 'sql'))
514 
515     for model in app_models:
516         output.extend(custom_sql_for_model(model, style))
517@@ -161,7 +161,7 @@
518     from django.conf import settings
519 
520     opts = model._meta
521-    app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
522+    app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).app_module.__file__), 'sql'))
523     output = []
524 
525     # Post-creation SQL should come before any initial SQL data is loaded.
526@@ -197,7 +197,7 @@
527     from django.dispatch import dispatcher
528     # Emit the post_sync signal for every application.
529     for app in models.get_apps():
530-        app_name = app.__name__.split('.')[-2]
531+        app_name = app.label
532         if verbosity >= 2:
533             print "Running post-sync handlers for application", app_name
534         models.signals.post_syncdb.send(sender=app, app=app,
535Index: django/templatetags/__init__.py
536===================================================================
537--- django/templatetags/__init__.py     (revision 8965)
538+++ django/templatetags/__init__.py     (working copy)
539@@ -1,6 +1,6 @@
540-from django.conf import settings
541+from django.conf import settings, get_installed_app_paths
542 
543-for a in settings.INSTALLED_APPS:
544+for a in get_installed_app_paths():
545     try:
546         __path__.extend(__import__(a + '.templatetags', {}, {}, ['']).__path__)
547     except ImportError:
548Index: django/views/i18n.py
549===================================================================
550--- django/views/i18n.py        (revision 8965)
551+++ django/views/i18n.py        (working copy)
552@@ -1,7 +1,7 @@
553 from django import http
554 from django.utils.translation import check_for_language, activate, to_locale, get_language
555 from django.utils.text import javascript_quote
556-from django.conf import settings
557+from django.conf import settings, get_installed_app_paths
558 import os
559 import gettext as gettext_module
560 
561@@ -121,7 +121,7 @@
562         packages = ['django.conf']
563     if type(packages) in (str, unicode):
564         packages = packages.split('+')
565-    packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
566+    packages = [p for p in packages if p == 'django.conf' or p in get_installed_app_paths()]
567     default_locale = to_locale(settings.LANGUAGE_CODE)
568     locale = to_locale(get_language())
569     t = {}
570Index: django/contrib/sites/management.py
571===================================================================
572--- django/contrib/sites/management.py  (revision 8965)
573+++ django/contrib/sites/management.py  (working copy)
574@@ -2,9 +2,8 @@
575 Creates the default Site object.
576 """
577 
578-from django.db.models import signals
579+from django.db.models import signals, find_app
580 from django.contrib.sites.models import Site
581-from django.contrib.sites import models as site_app
582 
583 def create_default_site(app, created_models, verbosity, **kwargs):
584     if Site in created_models:
585@@ -14,4 +13,4 @@
586         s.save()
587     Site.objects.clear_cache()
588 
589-signals.post_syncdb.connect(create_default_site, sender=site_app)
590+signals.post_syncdb.connect(create_default_site, sender=find_app('django.contrib.sites'))
591Index: django/contrib/contenttypes/management.py
592===================================================================
593--- django/contrib/contenttypes/management.py   (revision 8965)
594+++ django/contrib/contenttypes/management.py   (working copy)
595@@ -8,7 +8,7 @@
596     entries that no longer have a matching model class.
597     """
598     ContentType.objects.clear_cache()
599-    content_types = list(ContentType.objects.filter(app_label=app.__name__.split('.')[-2]))
600+    content_types = list(ContentType.objects.filter(app_label=app.label))
601     app_models = get_models(app)
602     if not app_models:
603         return
604Index: django/utils/translation/trans_real.py
605===================================================================
606--- django/utils/translation/trans_real.py      (revision 8965)
607+++ django/utils/translation/trans_real.py      (working copy)
608@@ -114,7 +114,7 @@
609     if t is not None:
610         return t
611 
612-    from django.conf import settings
613+    from django.conf import settings, get_installed_app_paths
614 
615     # set up the right translation class
616     klass = DjangoTranslation
617@@ -175,7 +175,7 @@
618         if projectpath and os.path.isdir(projectpath):
619             res = _merge(projectpath)
620 
621-        for appname in settings.INSTALLED_APPS:
622+        for appname in get_installed_app_paths():
623             p = appname.rfind('.')
624             if p >= 0:
625                 app = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:])
626Index: django/template/loaders/app_directories.py
627===================================================================
628--- django/template/loaders/app_directories.py  (revision 8965)
629+++ django/template/loaders/app_directories.py  (working copy)
630@@ -5,14 +5,14 @@
631 
632 import os
633 
634-from django.conf import settings
635+from django.conf import settings, get_installed_app_paths
636 from django.core.exceptions import ImproperlyConfigured
637 from django.template import TemplateDoesNotExist
638 from django.utils._os import safe_join
639 
640 # At compile time, cache the directories to search.
641 app_template_dirs = []
642-for app in settings.INSTALLED_APPS:
643+for app in get_installed_app_paths():
644     i = app.rfind('.')
645     if i == -1:
646         m, a = app, None
647Index: django/template/loaders/eggs.py
648===================================================================
649--- django/template/loaders/eggs.py     (revision 8965)
650+++ django/template/loaders/eggs.py     (working copy)
651@@ -6,7 +6,7 @@
652     resource_string = None
653 
654 from django.template import TemplateDoesNotExist
655-from django.conf import settings
656+from django.conf import settings, get_installed_app_paths
657 
658 def load_template_source(template_name, template_dirs=None):
659     """
660@@ -16,7 +16,7 @@
661     """
662     if resource_string is not None:
663         pkg_name = 'templates/' + template_name
664-        for app in settings.INSTALLED_APPS:
665+        for app in get_installed_app_paths():
666             try:
667                 return (resource_string(app, pkg_name).decode(settings.FILE_CHARSET), 'egg:%s:%s' % (app, pkg_name))
668             except:
669Index: tests/regressiontests/admin_scripts/tests.py
670===================================================================
671--- tests/regressiontests/admin_scripts/tests.py        (revision 8965)
672+++ tests/regressiontests/admin_scripts/tests.py        (working copy)
673@@ -969,9 +969,9 @@
674         args = ['app_command', 'auth']
675         out, err = self.run_manage(args)
676         self.assertNoOutput(err)
677-        self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
678-        self.assertOutput(out, os.sep.join(['django','contrib','auth','models.py']))
679-        self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
680+        self.assertOutput(out, "EXECUTE:AppCommand app=<app: django.contrib.auth>")
681+        #self.assertOutput(out, os.sep.join(['django','contrib','auth','models.py']))
682+        self.assertOutput(out, ">, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
683 
684     def test_app_command_no_apps(self):
685         "User AppCommands raise an error when no app name is provided"
686@@ -984,12 +984,12 @@
687         args = ['app_command','auth','contenttypes']
688         out, err = self.run_manage(args)
689         self.assertNoOutput(err)
690-        self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
691-        self.assertOutput(out, os.sep.join(['django','contrib','auth','models.py']))
692-        self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
693-        self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.contenttypes.models'")
694-        self.assertOutput(out, os.sep.join(['django','contrib','contenttypes','models.py']))
695-        self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
696+        self.assertOutput(out, "EXECUTE:AppCommand app=<app: django.contrib.auth>")
697+        #self.assertOutput(out, os.sep.join(['django','contrib','auth','models.py']))
698+        self.assertOutput(out, ">, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
699+        self.assertOutput(out, "EXECUTE:AppCommand app=<app: django.contrib.contenttypes>")
700+        #self.assertOutput(out, os.sep.join(['django','contrib','contenttypes','models.py']))
701+        self.assertOutput(out, ">, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
702 
703     def test_app_command_invalid_appname(self):
704         "User AppCommands can execute when a single app name is provided"
705Index: tests/runtests.py
706===================================================================
707--- tests/runtests.py   (revision 8965)
708+++ tests/runtests.py   (working copy)
709@@ -2,6 +2,7 @@
710 
711 import os, sys, traceback
712 import unittest
713+from django.conf import app, get_installed_app_paths
714 
715 import django.contrib as contrib
716 
717@@ -23,7 +24,8 @@
718 
719 ALWAYS_INSTALLED_APPS = [
720     'django.contrib.contenttypes',
721-    'django.contrib.auth',
722+    #We need to use the same app label, otherwise fixtures will break...
723+    app('django.contrib.auth', 'auth', 'Authentication'),
724     'django.contrib.sites',
725     'django.contrib.flatpages',
726     'django.contrib.redirects',
727@@ -58,13 +60,14 @@
728 
729     def runTest(self):
730         from django.core.management.validation import get_validation_errors
731-        from django.db.models.loading import load_app
732+        from django.db.models.loading import load_app, find_app
733         from cStringIO import StringIO
734 
735         try:
736             module = load_app(self.model_label)
737+            app = find_app(self.model_label)
738         except Exception, e:
739-            self.fail('Unable to load invalid model module')
740+            self.fail('Unable to load invalid application %s: %s' % (self.model_label, e))
741 
742         # Make sure sys.stdout is not a tty so that we get errors without
743         # coloring attached (makes matching the results easier). We restore
744@@ -72,7 +75,7 @@
745         orig_stdout = sys.stdout
746         s = StringIO()
747         sys.stdout = s
748-        count = get_validation_errors(s, module)
749+        count = get_validation_errors(s, app)
750         sys.stdout = orig_stdout
751         s.seek(0)
752         error_log = s.read()
753@@ -129,7 +132,7 @@
754                     print "Importing model %s" % model_name
755                 mod = load_app(model_label)
756                 if mod:
757-                    if model_label not in settings.INSTALLED_APPS:
758+                    if model_label not in get_installed_app_paths():
759                         settings.INSTALLED_APPS.append(model_label)
760         except Exception, e:
761             sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:]))