Code

Ticket #3591: custom-app-labels.diff

File custom-app-labels.diff, 20.6 KB (added by jkocherhans, 7 years ago)

A couple of internal tests are still broken, but admin, manage.py, etc. work

Line 
1Index: django/test/client.py
2===================================================================
3--- django/test/client.py       (revision 4615)
4+++ django/test/client.py       (working copy)
5@@ -167,7 +167,7 @@
6         if response.cookies:
7             self.cookies.update(response.cookies)
8 
9-        if 'django.contrib.sessions' in settings.INSTALLED_APPS:
10+        if 'django.contrib.sessions' in [app.path for app in settings.INSTALLED_APPS]:
11             from django.contrib.sessions.middleware import SessionWrapper
12             cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
13             if cookie:
14Index: django/db/models/base.py
15===================================================================
16--- django/db/models/base.py    (revision 4615)
17+++ django/db/models/base.py    (working copy)
18@@ -8,7 +8,7 @@
19 from django.db.models.options import Options, AdminOptions
20 from django.db import connection, backend, transaction
21 from django.db.models import signals
22-from django.db.models.loading import register_models, get_model
23+from django.db.models.loading import register_models, get_model, get_app_label
24 from django.dispatch import dispatcher
25 from django.utils.datastructures import SortedDict
26 from django.utils.functional import curry
27@@ -42,7 +42,8 @@
28         if getattr(new_class._meta, 'app_label', None) is None:
29             # Figure out the app_label by looking one level up.
30             # For 'django.contrib.sites.models', this would be 'sites'.
31-            new_class._meta.app_label = model_module.__name__.split('.')[-2]
32+            new_class._meta.app_label = get_app_label(new_class)
33+            #new_class._meta.app_label = model_module.__name__.split('.')[-2]
34 
35         # Bail out early if we have already created this class.
36         m = get_model(new_class._meta.app_label, name, False)
37Index: django/db/models/options.py
38===================================================================
39--- django/db/models/options.py (revision 4615)
40+++ django/db/models/options.py (working copy)
41@@ -36,7 +36,7 @@
42 
43     def contribute_to_class(self, cls, name):
44         cls._meta = self
45-        self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
46+        self.installed = re.sub('\.models$', '', cls.__module__) in [app.path for app in settings.INSTALLED_APPS]
47         # First, construct the default values for these options.
48         self.object_name = cls.__name__
49         self.module_name = self.object_name.lower()
50Index: django/db/models/loading.py
51===================================================================
52--- django/db/models/loading.py (revision 4615)
53+++ django/db/models/loading.py (working copy)
54@@ -1,6 +1,6 @@
55 "Utilities for loading models and the modules that contain them."
56 
57-from django.conf import settings
58+from django.conf import settings, directives
59 from django.core.exceptions import ImproperlyConfigured
60 import sys
61 import os
62@@ -24,20 +24,20 @@
63     global _loaded
64     if not _loaded:
65         _loaded = True
66-        for app_name in settings.INSTALLED_APPS:
67+        for app in settings.INSTALLED_APPS:
68             try:
69-                load_app(app_name)
70+                load_app(app.path)
71             except Exception, e:
72                 # Problem importing the app
73-                _app_errors[app_name] = e
74+                _app_errors[app.path] = e
75     return _app_list
76 
77 def get_app(app_label, emptyOK=False):
78     "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
79     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
80-    for app_name in settings.INSTALLED_APPS:
81-        if app_label == app_name.split('.')[-1]:
82-            mod = load_app(app_name)
83+    for app in settings.INSTALLED_APPS:
84+        if app_label == app.app_label:
85+            mod = load_app(app.path)
86             if mod is None:
87                 if emptyOK:
88                     return None
89@@ -61,18 +61,22 @@
90     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
91     return _app_errors
92 
93-def get_models(app_mod=None):
94+def get_models(app=None):
95     """
96-    Given a module containing models, returns a list of the models. Otherwise
97-    returns a list of all installed models.
98+    Given a app config directive, returns a list of the models in that app.
99+    Otherwise returns a list of all installed models.
100     """
101     app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
102-    if app_mod:
103-        return _app_models.get(app_mod.__name__.split('.')[-2], {}).values()
104+    if app:
105+        if isinstance(app, str):
106+            print app
107+            app = app_for_label(app)
108+            print app
109+        return _app_models.get(app.app_label, {}).values()
110     else:
111         model_list = []
112-        for app_mod in app_list:
113-            model_list.extend(get_models(app_mod))
114+        for app in settings.INSTALLED_APPS:
115+            model_list.extend(get_models(app))
116         return model_list
117 
118 def get_model(app_label, model_name, seed_cache=True):
119@@ -114,3 +118,27 @@
120             if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
121                 continue
122         model_dict[model_name] = model
123+
124+def get_app_label(model):
125+    model_module_path = model.__module__
126+    model_module_path_list = model_module_path.split('.')
127+    model_module_index = model_module_path_list.index('models')
128+    app_module_path_list = model_module_path_list[:model_module_index]
129+    app_module_path = '.'.join(app_module_path_list)   
130+    for app in settings.INSTALLED_APPS:
131+        if app_module_path == app.path:
132+            return app.app_label
133+    # app is most likely not installed, but give it an app label using the old method
134+    return model.__module__.split('.')[-2]
135+
136+def app_for_path(path):
137+    for app in settings.INSTALLED_APPS:
138+        if path == app.path:
139+            return app
140+    # app is most likely not installed, but give it an app label using the old method
141+    return directives.app(path.split('.')[-1])
142+
143+def app_for_label(app_label):
144+    for app in settings.INSTALLED_APPS:
145+        if app_label == app.app_label:
146+            return app
147Index: django/conf/__init__.py
148===================================================================
149--- django/conf/__init__.py     (revision 4615)
150+++ django/conf/__init__.py     (working copy)
151@@ -8,7 +8,8 @@
152 
153 import os
154 import time     # Needed for Windows
155-from django.conf import global_settings
156+from django.conf import global_settings, directives
157+from django.utils.datastructures import SortedDict
158 
159 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
160 
161@@ -94,14 +95,19 @@
162                 setattr(self, setting, setting_value)
163 
164         # Expand entries in INSTALLED_APPS like "django.contrib.*" to a list
165-        # of all those apps.
166+        # of all those apps. Also, convert strings into app directives.
167         new_installed_apps = []
168         for app in self.INSTALLED_APPS:
169-            if app.endswith('.*'):
170-                appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__)
171-                for d in os.listdir(appdir):
172-                    if d.isalpha() and os.path.isdir(os.path.join(appdir, d)):
173-                        new_installed_apps.append('%s.%s' % (app[:-2], d))
174+            if isinstance(app, str):
175+                if app.endswith('.*'):
176+                    appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__)
177+                    for d in os.listdir(appdir):
178+                        if d.isalpha() and os.path.isdir(os.path.join(appdir, d)):
179+                            new_app = directives.app('%s.%s' % (app[:-2], d))
180+                            new_installed_apps.append(new_app)
181+                else:
182+                    new_app = directives.app(app)
183+                    new_installed_apps.append(new_app)
184             else:
185                 new_installed_apps.append(app)
186         self.INSTALLED_APPS = new_installed_apps
187Index: django/conf/directives.py
188===================================================================
189--- django/conf/directives.py   (revision 0)
190+++ django/conf/directives.py   (revision 0)
191@@ -0,0 +1,14 @@
192+class app(object):
193+    """Configuration directive for specifying an app."""
194+    def __init__(self, path, app_label=None, verbose_name=None):
195+        self.path = path
196+        # if name isn't specified, get the last part of the python dotted path
197+        self.app_label = app_label or path.split('.')[-1]
198+        self.verbose_name = verbose_name or self.app_label
199+
200+class backend(object):
201+    """Configuration directive for specifying an authentication backend."""
202+    def __init__(self, path, name=None):
203+        self.path = path
204+        # if name isn't specified, get the last part of the python dotted path
205+        self.name = name or path.split('.')[-1]
206Index: django/core/management.py
207===================================================================
208--- django/core/management.py   (revision 4615)
209+++ django/core/management.py   (working copy)
210@@ -56,10 +56,7 @@
211 def _get_installed_models(table_list):
212     "Gets a set of all models that are installed, given a list of existing tables"
213     from django.db import models
214-    all_models = []
215-    for app in models.get_apps():
216-        for model in models.get_models(app):
217-            all_models.append(model)
218+    all_models = models.get_models()
219     return set([m for m in all_models if m._meta.db_table in table_list])
220 
221 def _get_table_list():
222@@ -363,11 +360,12 @@
223 
224 def get_sql_initial_data(app):
225     "Returns a list of the initial INSERT SQL statements for the given app."
226-    from django.db.models import get_models
227+    from django.db import models
228     output = []
229 
230-    app_models = get_models(app)
231-    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
232+    app_models = models.get_models(app)
233+    app_module = models.get_app(app.app_label)
234+    app_dir = os.path.normpath(os.path.join(os.path.dirname(app_module.__file__), 'sql'))
235 
236     for model in app_models:
237         output.extend(get_sql_initial_data_for_model(model))
238@@ -450,9 +448,9 @@
239 
240     # Import the 'management' module within each installed app, to register
241     # dispatcher events.
242-    for app_name in settings.INSTALLED_APPS:
243+    for app in settings.INSTALLED_APPS:
244         try:
245-            __import__(app_name + '.management', {}, {}, [''])
246+            __import__(app.path + '.management', {}, {}, [''])
247         except ImportError:
248             pass
249 
250@@ -469,8 +467,8 @@
251     created_models = set()
252     pending_references = {}
253 
254-    for app in models.get_apps():
255-        app_name = app.__name__.split('.')[-2]
256+    for app in settings.INSTALLED_APPS:
257+        app_name = app.path
258         model_list = models.get_models(app)
259         for model in model_list:
260             # Create the model's database table, if it doesn't already exist.
261@@ -503,11 +501,12 @@
262 
263     # Send the post_syncdb signal, so individual apps can do whatever they need
264     # to do at this point.
265-    for app in models.get_apps():
266-        app_name = app.__name__.split('.')[-2]
267+    for app in settings.INSTALLED_APPS:
268+        app_name = app.path
269+        app_module = models.get_app(app.app_label)
270         if verbosity >= 2:
271             print "Running post-sync handlers for application", app_name
272-        dispatcher.send(signal=signals.post_syncdb, sender=app,
273+        dispatcher.send(signal=signals.post_syncdb, sender=app_module,
274             app=app, created_models=created_models,
275             verbosity=verbosity, interactive=interactive)
276 
277@@ -530,8 +529,8 @@
278                         transaction.commit_unless_managed()
279 
280     # Install SQL indicies for all newly created models
281-    for app in models.get_apps():
282-        app_name = app.__name__.split('.')[-2]
283+    for app in settings.INSTALLED_APPS:
284+        app_name = app.path
285         for model in models.get_models(app):
286             if model in created_models:
287                 index_sql = get_sql_indexes_for_model(model)
288@@ -1402,21 +1401,22 @@
289         action_mapping[action](args[1:])
290     else:
291         from django.db import models
292+        from django.conf import settings
293         validate(silent_success=True)
294         try:
295-            mod_list = [models.get_app(app_label) for app_label in args[1:]]
296+            app_list = [app for app in settings.INSTALLED_APPS if app.app_label in args[1:]]
297         except ImportError, e:
298             sys.stderr.write(style.ERROR("Error: %s. Are you sure your INSTALLED_APPS setting is correct?\n" % e))
299             sys.exit(1)
300-        if not mod_list:
301+        if not app_list:
302             parser.print_usage_and_exit()
303         if action not in NO_SQL_TRANSACTION:
304             print style.SQL_KEYWORD("BEGIN;")
305-        for mod in mod_list:
306+        for app in app_list:
307             if action == 'reset':
308-                output = action_mapping[action](mod, options.interactive)
309+                output = action_mapping[action](app, options.interactive)
310             else:
311-                output = action_mapping[action](mod)
312+                output = action_mapping[action](app)
313             if output:
314                 print '\n'.join(output)
315         if action not in NO_SQL_TRANSACTION:
316Index: django/templatetags/__init__.py
317===================================================================
318--- django/templatetags/__init__.py     (revision 4615)
319+++ django/templatetags/__init__.py     (working copy)
320@@ -1,7 +1,7 @@
321 from django.conf import settings
322 
323-for a in settings.INSTALLED_APPS:
324+for app in settings.INSTALLED_APPS:
325     try:
326-        __path__.extend(__import__(a + '.templatetags', {}, {}, ['']).__path__)
327+        __path__.extend(__import__(app.path + '.templatetags', {}, {}, ['']).__path__)
328     except ImportError:
329         pass
330Index: django/views/i18n.py
331===================================================================
332--- django/views/i18n.py        (revision 4615)
333+++ django/views/i18n.py        (working copy)
334@@ -104,7 +104,7 @@
335         packages = ['django.conf']
336     if type(packages) in (str, unicode):
337         packages = packages.split('+')
338-    packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
339+    packages = [p for p in packages if p == 'django.conf' or p in [app.path for app in settings.INSTALLED_APPS]]
340     default_locale = to_locale(settings.LANGUAGE_CODE)
341     locale = to_locale(get_language())
342     t = {}
343Index: django/contrib/admin/templatetags/adminapplist.py
344===================================================================
345--- django/contrib/admin/templatetags/adminapplist.py   (revision 4615)
346+++ django/contrib/admin/templatetags/adminapplist.py   (working copy)
347@@ -1,5 +1,6 @@
348 from django import template
349 from django.db.models import get_models
350+from django.conf import settings
351 
352 register = template.Library()
353 
354@@ -13,12 +14,12 @@
355         app_list = []
356         user = context['user']
357 
358-        for app in models.get_apps():
359+        for app in settings.INSTALLED_APPS:
360             # Determine the app_label.
361             app_models = get_models(app)
362             if not app_models:
363                 continue
364-            app_label = app_models[0]._meta.app_label
365+            app_label = app.app_label
366 
367             has_module_perms = user.has_module_perms(app_label)
368 
369@@ -49,7 +50,7 @@
370                     model_list = [x for key, x in decorated]
371 
372                     app_list.append({
373-                        'name': app_label.title(),
374+                        'name': app.verbose_name.title(),
375                         'has_module_perms': has_module_perms,
376                         'models': model_list,
377                     })
378Index: django/utils/translation/trans_real.py
379===================================================================
380--- django/utils/translation/trans_real.py      (revision 4615)
381+++ django/utils/translation/trans_real.py      (working copy)
382@@ -161,14 +161,15 @@
383         if projectpath and os.path.isdir(projectpath):
384             res = _merge(projectpath)
385 
386-        for appname in settings.INSTALLED_APPS:
387+        for app in settings.INSTALLED_APPS:
388+            appname = app.path
389             p = appname.rfind('.')
390             if p >= 0:
391-                app = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:])
392+                app_module = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:])
393             else:
394-                app = __import__(appname, {}, {}, [])
395+                app_module = __import__(appname, {}, {}, [])
396 
397-            apppath = os.path.join(os.path.dirname(app.__file__), 'locale')
398+            apppath = os.path.join(os.path.dirname(app_module.__file__), 'locale')
399 
400             if os.path.isdir(apppath):
401                 res = _merge(apppath)
402Index: django/template/loaders/app_directories.py
403===================================================================
404--- django/template/loaders/app_directories.py  (revision 4615)
405+++ django/template/loaders/app_directories.py  (working copy)
406@@ -8,18 +8,18 @@
407 # At compile time, cache the directories to search.
408 app_template_dirs = []
409 for app in settings.INSTALLED_APPS:
410-    i = app.rfind('.')
411+    i = app.path.rfind('.')
412     if i == -1:
413-        m, a = app, None
414+        m, a = app.path, None
415     else:
416-        m, a = app[:i], app[i+1:]
417+        m, a = app.path[:i], app.path[i+1:]
418     try:
419         if a is None:
420             mod = __import__(m, {}, {}, [])
421         else:
422             mod = getattr(__import__(m, {}, {}, [a]), a)
423     except ImportError, e:
424-        raise ImproperlyConfigured, 'ImportError %s: %s' % (app, e.args[0])
425+        raise ImproperlyConfigured, 'ImportError %s: %s' % (app.path, e.args[0])
426     template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates')
427     if os.path.isdir(template_dir):
428         app_template_dirs.append(template_dir)
429Index: django/template/loaders/eggs.py
430===================================================================
431--- django/template/loaders/eggs.py     (revision 4615)
432+++ django/template/loaders/eggs.py     (working copy)
433@@ -18,7 +18,7 @@
434         pkg_name = 'templates/' + template_name
435         for app in settings.INSTALLED_APPS:
436             try:
437-                return (resource_string(app, pkg_name), 'egg:%s:%s ' % (app, pkg_name))
438+                return (resource_string(app.path, pkg_name), 'egg:%s:%s ' % (app.path, pkg_name))
439             except:
440                 pass
441     raise TemplateDoesNotExist, template_name
442Index: tests/runtests.py
443===================================================================
444--- tests/runtests.py   (revision 4615)
445+++ tests/runtests.py   (working copy)
446@@ -2,6 +2,7 @@
447 
448 import os, sys, traceback
449 import unittest
450+from django.conf import directives
451 
452 MODEL_TESTS_DIR_NAME = 'modeltests'
453 REGRESSION_TESTS_DIR_NAME = 'regressiontests'
454@@ -12,14 +13,14 @@
455 REGRESSION_TEST_DIR = os.path.join(os.path.dirname(__file__), REGRESSION_TESTS_DIR_NAME)
456 
457 ALWAYS_INSTALLED_APPS = [
458-    'django.contrib.contenttypes',
459-    'django.contrib.auth',
460-    'django.contrib.sites',
461-    'django.contrib.flatpages',
462-    'django.contrib.redirects',
463-    'django.contrib.sessions',
464-    'django.contrib.comments',
465-    'django.contrib.admin',
466+    directives.app('django.contrib.contenttypes'),
467+    directives.app('django.contrib.auth'),
468+    directives.app('django.contrib.sites'),
469+    directives.app('django.contrib.flatpages'),
470+    directives.app('django.contrib.redirects'),
471+    directives.app('django.contrib.sessions'),
472+    directives.app('django.contrib.comments'),
473+    directives.app('django.contrib.admin'),
474 ]
475 
476 def get_test_models():
477@@ -48,16 +49,19 @@
478 
479     def runTest(self):
480         from django.core import management
481-        from django.db.models.loading import load_app
482+        from django.db.models.loading import load_app, app_for_path
483         from cStringIO import StringIO
484 
485         try:
486             module = load_app(self.model_label)
487+            app = app_for_path(self.model_label)
488         except Exception, e:
489+            print self.model_label
490+            print e
491             self.fail('Unable to load invalid model module')
492 
493         s = StringIO()
494-        count = management.get_validation_errors(s, module)
495+        count = management.get_validation_errors(s, app)
496         s.seek(0)
497         error_log = s.read()
498         actual = error_log.split('\n')
499@@ -108,8 +112,9 @@
500             if not tests_to_run or model_name in tests_to_run:
501                 if verbosity >= 1:
502                     print "Importing model %s" % model_name
503+                app = directives.app(model_label)
504+                settings.INSTALLED_APPS.append(app)
505                 mod = load_app(model_label)
506-                settings.INSTALLED_APPS.append(model_label)
507                 test_models.append(mod)
508         except Exception, e:
509             sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:]))