Browse Source

Merge "Fix compatibility issues with Django 1.10" into stable/newton

tags/10.0.0.0rc2
Jenkins 2 years ago
parent
commit
c2eaffeb2a

+ 8
- 1
horizon/base.py View File

@@ -26,6 +26,7 @@ import inspect
26 26
 import logging
27 27
 import os
28 28
 
29
+import django
29 30
 from django.conf import settings
30 31
 from django.conf.urls import include
31 32
 from django.conf.urls import url
@@ -54,7 +55,13 @@ LOG = logging.getLogger(__name__)
54 55
 def _decorate_urlconf(urlpatterns, decorator, *args, **kwargs):
55 56
     for pattern in urlpatterns:
56 57
         if getattr(pattern, 'callback', None):
57
-            pattern._callback = decorator(pattern.callback, *args, **kwargs)
58
+            decorated = decorator(pattern.callback, *args, **kwargs)
59
+            if django.VERSION >= (1, 10):
60
+                pattern.callback = decorated
61
+            else:
62
+                # prior to 1.10 callback was a property and we had
63
+                # to modify the private attribute behind the property
64
+                pattern._callback = decorated
58 65
         if getattr(pattern, 'url_patterns', []):
59 66
             _decorate_urlconf(pattern.url_patterns, decorator, *args, **kwargs)
60 67
 

+ 3
- 3
horizon/templatetags/breadcrumb_nav.py View File

@@ -48,13 +48,13 @@ def breadcrumb_nav(context):
48 48
     custom_breadcrumb = context.get('custom_breadcrumb')
49 49
 
50 50
     # Build list of tuples (name, optional url)
51
-    breadcrumb.append((dashboard.name,))
51
+    breadcrumb.append((dashboard.name, None))
52 52
     if panel_group:
53
-        breadcrumb.append((panel_group.name,))
53
+        breadcrumb.append((panel_group.name, None))
54 54
     if panel:
55 55
         breadcrumb.append((panel.name, panel.get_absolute_url()))
56 56
     if custom_breadcrumb:
57 57
         breadcrumb.extend(custom_breadcrumb)
58
-    breadcrumb.append((context.get('page_title'),))
58
+    breadcrumb.append((context.get('page_title'), None))
59 59
 
60 60
     return {'breadcrumb': breadcrumb}

+ 22
- 16
horizon/test/settings.py View File

@@ -31,7 +31,6 @@ ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
31 31
 STATIC_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'static'))
32 32
 
33 33
 DEBUG = False
34
-TEMPLATE_DEBUG = DEBUG
35 34
 TESTSERVER = 'http://testserver'
36 35
 
37 36
 SECRET_KEY = 'elj1IWiLoWHgcyYxFVLj7cM5rGOOxWl0'
@@ -73,20 +72,28 @@ MIDDLEWARE_CLASSES = (
73 72
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
74 73
 )
75 74
 
76
-TEMPLATE_CONTEXT_PROCESSORS = (
77
-    'django.core.context_processors.debug',
78
-    'django.core.context_processors.i18n',
79
-    'django.core.context_processors.request',
80
-    'django.core.context_processors.media',
81
-    'django.core.context_processors.static',
82
-    'django.contrib.messages.context_processors.messages',
83
-    'horizon.context_processors.horizon')
84
-
85
-TEMPLATE_LOADERS = (
86
-    'django.template.loaders.filesystem.Loader',
87
-    'django.template.loaders.app_directories.Loader',
88
-    'horizon.loaders.TemplateLoader'
89
-)
75
+TEMPLATES = [
76
+    {
77
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
78
+        'DIRS': [os.path.join(ROOT_PATH, 'tests', 'templates')],
79
+        'OPTIONS': {
80
+            'context_processors': [
81
+                'django.template.context_processors.debug',
82
+                'django.template.context_processors.i18n',
83
+                'django.template.context_processors.request',
84
+                'django.template.context_processors.media',
85
+                'django.template.context_processors.static',
86
+                'django.contrib.messages.context_processors.messages',
87
+                'horizon.context_processors.horizon',
88
+            ],
89
+            'loaders': [
90
+                'django.template.loaders.filesystem.Loader',
91
+                'django.template.loaders.app_directories.Loader',
92
+                'horizon.loaders.TemplateLoader'
93
+            ],
94
+        },
95
+    },
96
+]
90 97
 
91 98
 STATIC_URL = '/static/'
92 99
 WEBROOT = '/'
@@ -94,7 +101,6 @@ WEBROOT = '/'
94 101
 MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
95 102
 
96 103
 ROOT_URLCONF = 'horizon.test.urls'
97
-TEMPLATE_DIRS = (os.path.join(ROOT_PATH, 'tests', 'templates'),)
98 104
 SITE_ID = 1
99 105
 SITE_BRANDING = 'Horizon'
100 106
 

+ 1
- 2
openstack_dashboard/dashboards/admin/hypervisors/views.py View File

@@ -67,7 +67,6 @@ class AdminDetailView(tables.DataTableView):
67 67
     def get_context_data(self, **kwargs):
68 68
         context = super(AdminDetailView, self).get_context_data(**kwargs)
69 69
         hypervisor_name = self.kwargs['hypervisor'].split('_', 1)[1]
70
-        breadcrumb = [
71
-            (hypervisor_name,), ]
70
+        breadcrumb = [(hypervisor_name, None)]
72 71
         context['custom_breadcrumb'] = breadcrumb
73 72
         return context

+ 2
- 1
openstack_dashboard/dashboards/admin/networks/ports/views.py View File

@@ -87,7 +87,8 @@ class DetailView(project_views.DetailView):
87 87
         breadcrumb = [
88 88
             (_("Networks"), self.get_redirect_url()),
89 89
             ((port.network_name or port.network_id), port.network_url),
90
-            (_("Ports"),), ]
90
+            (_("Ports"), None)
91
+        ]
91 92
         context["custom_breadcrumb"] = breadcrumb
92 93
         context["url"] = \
93 94
             reverse('horizon:admin:networks:ports_tab', args=[port.network_id])

+ 10
- 5
openstack_dashboard/dashboards/identity/projects/tests.py View File

@@ -17,6 +17,7 @@ import logging
17 17
 import os
18 18
 import unittest
19 19
 
20
+import django
20 21
 from django.core.urlresolvers import reverse
21 22
 from django import http
22 23
 from django.test.utils import override_settings
@@ -288,11 +289,15 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
288 289
         res = self.client.get(reverse('horizon:identity:projects:create'))
289 290
 
290 291
         self.assertTemplateUsed(res, views.WorkflowView.template_name)
291
-        self.assertContains(res, '''
292
-                            <input class="form-control"
293
-                            id="id_subnet" min="-1"
294
-                            name="subnet" type="number" value="10" />
295
-                            ''', html=True)
292
+        if django.VERSION >= (1, 10):
293
+            pattern = ('<input class="form-control" '
294
+                       'id="id_subnet" min="-1" '
295
+                       'name="subnet" type="number" value="10" required/>')
296
+        else:
297
+            pattern = ('<input class="form-control" '
298
+                       'id="id_subnet" min="-1" '
299
+                       'name="subnet" type="number" value="10"/>')
300
+        self.assertContains(res, pattern, html=True)
296 301
 
297 302
         workflow = res.context['workflow']
298 303
         self.assertEqual(res.context['workflow'].name,

+ 11
- 3
openstack_dashboard/dashboards/project/containers/tests.py View File

@@ -20,6 +20,7 @@ import copy
20 20
 import email.header
21 21
 import tempfile
22 22
 
23
+import django
23 24
 from django.core.files.uploadedfile import InMemoryUploadedFile  # noqa
24 25
 from django.core.urlresolvers import reverse
25 26
 from django import http
@@ -436,9 +437,16 @@ class SwiftTests(test.TestCase):
436 437
                            args=[container.name, obj.name])
437 438
         res = self.client.get(copy_url)
438 439
         # The copy's name must appear in initial data
439
-        pattern = ('<input id="id_new_object_name" value="%s" '
440
-                   'name="new_object_name" type="text" '
441
-                   'class="form-control" maxlength="255" />' % copy_name)
440
+        if django.VERSION >= (1, 10):
441
+            pattern = ('<input id="id_new_object_name" value="%s" '
442
+                       'name="new_object_name" type="text" '
443
+                       'class="form-control" '
444
+                       'maxlength="255" required/>' % copy_name)
445
+        else:
446
+            pattern = ('<input id="id_new_object_name" value="%s" '
447
+                       'name="new_object_name" type="text" '
448
+                       'class="form-control" '
449
+                       'maxlength="255"/>' % copy_name)
442 450
         self.assertContains(res, pattern, html=True)
443 451
 
444 452
     def test_get_copy_name(self):

+ 2
- 1
openstack_dashboard/dashboards/project/loadbalancers/views.py View File

@@ -139,7 +139,8 @@ class VipDetailsView(tabs.TabView):
139 139
             (vip_nav,
140 140
              reverse('horizon:project:loadbalancers:vipdetails',
141 141
                      args=(vip.id,))),
142
-            (_("VIP"),), ]
142
+            (_("VIP"), None)
143
+        ]
143 144
         context["custom_breadcrumb"] = breadcrumb
144 145
         return context
145 146
 

+ 2
- 1
openstack_dashboard/dashboards/project/networks/ports/views.py View File

@@ -90,7 +90,8 @@ class DetailView(tabs.TabbedTableView):
90 90
         # TODO(robcresswell) Add URL for "Ports" crumb after bug/1416838
91 91
         breadcrumb = [
92 92
             ((port.network_name or port.network_id), port.network_url),
93
-            (_("Ports"),), ]
93
+            (_("Ports"), None)
94
+        ]
94 95
         context["custom_breadcrumb"] = breadcrumb
95 96
         context["port"] = port
96 97
         context["url"] = self.get_redirect_url()

+ 2
- 1
openstack_dashboard/dashboards/project/networks/subnets/views.py View File

@@ -154,7 +154,8 @@ class DetailView(tabs.TabView):
154 154
         # TODO(robcresswell) Add URL for "Subnets" crumb after bug/1416838
155 155
         breadcrumb = [
156 156
             (network_nav, subnet.network_url),
157
-            (_("Subnets"),), ]
157
+            (_("Subnets"), None)
158
+        ]
158 159
         context["custom_breadcrumb"] = breadcrumb
159 160
         context["subnet"] = subnet
160 161
         context["url"] = \

+ 10
- 5
openstack_dashboard/dashboards/project/routers/tests.py View File

@@ -13,6 +13,7 @@
13 13
 #    under the License.
14 14
 import copy
15 15
 
16
+import django
16 17
 from django.core.urlresolvers import reverse
17 18
 from django import http
18 19
 
@@ -441,11 +442,15 @@ class RouterActionTests(RouterMixin, test.TestCase):
441 442
 
442 443
         self.assertTemplateUsed(res, 'project/routers/update.html')
443 444
         self.assertContains(res, 'Router Type')
444
-        self.assertContains(
445
-            res,
446
-            '<input class="form-control" id="id_mode" name="mode" '
447
-            'readonly="readonly" type="text" value="distributed" />',
448
-            html=True)
445
+        if django.VERSION >= (1, 10):
446
+            pattern = ('<input class="form-control" id="id_mode" name="mode" '
447
+                       'readonly="readonly" type="text" value="distributed" '
448
+                       'required/>')
449
+        else:
450
+            pattern = ('<input class="form-control" id="id_mode" name="mode" '
451
+                       'readonly="readonly" type="text" '
452
+                       'value="distributed" />')
453
+        self.assertContains(res, pattern, html=True)
449 454
         self.assertNotContains(res, 'centralized')
450 455
 
451 456
     @test.create_stubs({api.neutron: ('router_get',

+ 38
- 34
openstack_dashboard/dashboards/project/stacks/tests.py View File

@@ -13,6 +13,7 @@
13 13
 import json
14 14
 import re
15 15
 
16
+import django
16 17
 from django.conf import settings
17 18
 from django.core import exceptions
18 19
 from django.core.urlresolvers import reverse
@@ -394,16 +395,25 @@ class StackTests(test.TestCase):
394 395
         self.assertTemplateUsed(res, 'project/stacks/create.html')
395 396
 
396 397
         # ensure the fields were rendered correctly
397
-        self.assertContains(res,
398
-                            '<input class="form-control" '
399
-                            'id="id___param_public_string" '
400
-                            'name="__param_public_string" '
401
-                            'type="text" />', html=True)
402
-        self.assertContains(res,
403
-                            '<input class="form-control" '
404
-                            'id="id___param_secret_string" '
405
-                            'name="__param_secret_string" '
406
-                            'type="password" />', html=True)
398
+        if django.VERSION >= (1, 10):
399
+            pattern = ('<input class="form-control" '
400
+                       'id="id___param_public_string" '
401
+                       'name="__param_public_string" type="text" required/>')
402
+            secret = ('<input class="form-control" '
403
+                      'id="id___param_secret_string" '
404
+                      'name="__param_secret_string" '
405
+                      'type="password" required>')
406
+        else:
407
+            pattern = ('<input class="form-control" '
408
+                       'id="id___param_public_string" '
409
+                       'name="__param_public_string" type="text" />')
410
+            secret = ('<input class="form-control" '
411
+                      'id="id___param_secret_string" '
412
+                      'name="__param_secret_string" '
413
+                      'type="password" />')
414
+
415
+        self.assertContains(res, pattern, html=True)
416
+        self.assertContains(res, secret, html=True)
407 417
 
408 418
     @test.create_stubs({api.heat: ('template_validate',)})
409 419
     def test_launch_stack_with_parameter_group(self):
@@ -560,30 +570,24 @@ class StackTests(test.TestCase):
560 570
         self.assertTemplateUsed(res, 'project/stacks/create.html')
561 571
 
562 572
         # ensure the fields were rendered correctly
563
-        self.assertContains(res,
564
-                            '<input class="form-control" '
565
-                            'id="id___param_param1" '
566
-                            'name="__param_param1" '
567
-                            'type="text" />', html=True)
568
-        self.assertContains(res,
569
-                            '<input class="form-control" '
570
-                            'id="id___param_param2" '
571
-                            'name="__param_param2" '
572
-                            'type="number" />', html=True)
573
-        self.assertContains(res,
574
-                            '<input class="form-control" '
575
-                            'id="id___param_param3" '
576
-                            'name="__param_param3" '
577
-                            'type="text" />', html=True)
578
-        self.assertContains(res,
579
-                            '<input class="form-control" '
580
-                            'id="id___param_param4" '
581
-                            'name="__param_param4" '
582
-                            'type="text" />', html=True)
583
-        self.assertContains(res,
584
-                            '<input id="id___param_param5" '
585
-                            'name="__param_param5" '
586
-                            'type="checkbox" />', html=True)
573
+        if django.VERSION >= (1, 10):
574
+            input_str = ('<input class="form-control" '
575
+                         'id="id___param_param{0}" '
576
+                         'name="__param_param{0}" type="{1}" required/>')
577
+        else:
578
+            input_str = ('<input class="form-control" '
579
+                         'id="id___param_param{0}" '
580
+                         'name="__param_param{0}" type="{1}"/>')
581
+
582
+        self.assertContains(res, input_str.format(1, 'text'), html=True)
583
+        self.assertContains(res, input_str.format(2, 'number'), html=True)
584
+        self.assertContains(res, input_str.format(3, 'text'), html=True)
585
+        self.assertContains(res, input_str.format(4, 'text'), html=True)
586
+        self.assertContains(
587
+            res,
588
+            '<input id="id___param_param5" name="__param_param5" '
589
+            'type="checkbox">',
590
+            html=True)
587 591
 
588 592
         # post some sample data and make sure it validates
589 593
         url = reverse('horizon:project:stacks:launch')

+ 1
- 1
openstack_dashboard/dashboards/project/volumes/volumes/tests.py View File

@@ -1093,7 +1093,7 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
1093 1093
     def _get_volume_row_action_from_ajax(self, res, action_name, row_id):
1094 1094
         def _matches_row_id(context_row):
1095 1095
             return (len(context_row.dicts) > 1 and
1096
-                    isinstance(context_row.dicts[1], dict) and
1096
+                    hasattr(context_row.dicts[1], 'get') and
1097 1097
                     context_row.dicts[1].get('row_id', None) == row_id)
1098 1098
 
1099 1099
         matching = list(moves.filter(lambda r: _matches_row_id(r),

+ 0
- 1
openstack_dashboard/local/local_settings.py.example View File

@@ -10,7 +10,6 @@ from openstack_dashboard import exceptions
10 10
 from openstack_dashboard.settings import HORIZON_CONFIG
11 11
 
12 12
 DEBUG = True
13
-TEMPLATE_DEBUG = DEBUG
14 13
 
15 14
 
16 15
 # WEBROOT is the location relative to Webserver root

+ 34
- 23
openstack_dashboard/settings.py View File

@@ -42,7 +42,6 @@ if ROOT_PATH not in sys.path:
42 42
     sys.path.append(ROOT_PATH)
43 43
 
44 44
 DEBUG = False
45
-TEMPLATE_DEBUG = DEBUG
46 45
 
47 46
 SITE_BRANDING = 'OpenStack Dashboard'
48 47
 
@@ -115,29 +114,35 @@ MIDDLEWARE_CLASSES = (
115 114
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
116 115
 )
117 116
 
118
-TEMPLATE_CONTEXT_PROCESSORS = (
119
-    'django.core.context_processors.debug',
120
-    'django.core.context_processors.i18n',
121
-    'django.core.context_processors.request',
122
-    'django.core.context_processors.media',
123
-    'django.core.context_processors.static',
124
-    'django.contrib.messages.context_processors.messages',
125
-    'horizon.context_processors.horizon',
126
-    'openstack_dashboard.context_processors.openstack',
127
-)
128
-
129
-TEMPLATE_LOADERS = ('horizon.themes.ThemeTemplateLoader',)
130
-
131
-CACHED_TEMPLATE_LOADERS = (
117
+CACHED_TEMPLATE_LOADERS = [
132 118
     'django.template.loaders.filesystem.Loader',
133 119
     'django.template.loaders.app_directories.Loader',
134
-    'horizon.loaders.TemplateLoader',)
120
+    'horizon.loaders.TemplateLoader'
121
+]
135 122
 
136 123
 ADD_TEMPLATE_LOADERS = []
137 124
 
138
-TEMPLATE_DIRS = (
139
-    os.path.join(ROOT_PATH, 'templates'),
140
-)
125
+TEMPLATES = [
126
+    {
127
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
128
+        'DIRS': [os.path.join(ROOT_PATH, 'templates')],
129
+        'OPTIONS': {
130
+            'context_processors': [
131
+                'django.template.context_processors.debug',
132
+                'django.template.context_processors.i18n',
133
+                'django.template.context_processors.request',
134
+                'django.template.context_processors.media',
135
+                'django.template.context_processors.static',
136
+                'django.contrib.messages.context_processors.messages',
137
+                'horizon.context_processors.horizon',
138
+                'openstack_dashboard.context_processors.openstack',
139
+            ],
140
+            'loaders': [
141
+                'horizon.themes.ThemeTemplateLoader'
142
+            ],
143
+        },
144
+    },
145
+]
141 146
 
142 147
 STATICFILES_FINDERS = (
143 148
     'django.contrib.staticfiles.finders.FileSystemFinder',
@@ -309,13 +314,19 @@ try:
309 314
 except ImportError:
310 315
     logging.warning("No local_settings file found.")
311 316
 
317
+# configure template debugging
318
+TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
319
+
312 320
 # Template loaders
313 321
 if DEBUG:
314
-    TEMPLATE_LOADERS += CACHED_TEMPLATE_LOADERS + tuple(ADD_TEMPLATE_LOADERS)
322
+    TEMPLATES[0]['OPTIONS']['loaders'].extend(
323
+        CACHED_TEMPLATE_LOADERS + ADD_TEMPLATE_LOADERS
324
+    )
315 325
 else:
316
-    TEMPLATE_LOADERS += (
317
-        ('django.template.loaders.cached.Loader', CACHED_TEMPLATE_LOADERS),
318
-    ) + tuple(ADD_TEMPLATE_LOADERS)
326
+    TEMPLATES[0]['OPTIONS']['loaders'].extend(
327
+        [('django.template.loaders.cached.Loader', CACHED_TEMPLATE_LOADERS)] +
328
+        ADD_TEMPLATE_LOADERS
329
+    )
319 330
 
320 331
 NG_TEMPLATE_CACHE_AGE = NG_TEMPLATE_CACHE_AGE if not DEBUG else 0
321 332
 

+ 7
- 6
openstack_dashboard/test/settings.py View File

@@ -36,8 +36,13 @@ WEBROOT = '/'
36 36
 SECRET_KEY = secret_key.generate_or_read_from_file(
37 37
     os.path.join(TEST_DIR, '.secret_key_store'))
38 38
 ROOT_URLCONF = 'openstack_dashboard.test.urls'
39
-TEMPLATE_DIRS = (
40
-    os.path.join(TEST_DIR, 'templates'),
39
+
40
+TEMPLATES[0]['DIRS'] = [
41
+    os.path.join(TEST_DIR, 'templates')
42
+]
43
+
44
+TEMPLATES[0]['OPTIONS']['context_processors'].append(
45
+    'openstack_dashboard.context_processors.openstack'
41 46
 )
42 47
 
43 48
 CUSTOM_THEME_PATH = 'themes/default'
@@ -58,10 +63,6 @@ AVAILABLE_THEMES = [
58 63
 # Theme Static Directory
59 64
 THEME_COLLECTION_DIR = 'themes'
60 65
 
61
-TEMPLATE_CONTEXT_PROCESSORS += (
62
-    'openstack_dashboard.context_processors.openstack',
63
-)
64
-
65 66
 COMPRESS_OFFLINE = False
66 67
 
67 68
 INSTALLED_APPS = (

+ 7
- 2
openstack_dashboard/test/tests/error_pages.py View File

@@ -25,7 +25,12 @@ class ErrorPageTests(test.TestCase):
25 25
     urls = 'openstack_dashboard.test.error_pages_urls'
26 26
 
27 27
     def test_500_error(self):
28
-        TEMPLATE_DIRS = (path.join(settings.ROOT_PATH, 'templates'),)
29
-        with self.settings(TEMPLATE_DIRS=TEMPLATE_DIRS):
28
+        with self.settings(
29
+                TEMPLATES=[{
30
+                    'DIRS': [path.join(settings.ROOT_PATH, 'templates')],
31
+                    'BACKEND': ('django.template.backends.django.'
32
+                                'DjangoTemplates')
33
+                }],
34
+                ROOT_URLCONF=self.urls):
30 35
             response = self.client.get('/500/')
31 36
             self.assertIn(b'Server error', response.content)

+ 10
- 0
releasenotes/notes/bp-dj110-438f26c21f283c46.yaml View File

@@ -0,0 +1,10 @@
1
+---
2
+upgrade:
3
+  - The ``TEMPLATE_*`` settings have been replaced with a ``TEMPLATE`` dict.
4
+    This will likely cause issues when porting settings to this version of
5
+    Horizon. The TEMPLATE_DEBUG setting has been removed and is tied to
6
+    the DEBUG setting now. A detailed explanation of this dict can be found at
7
+    https://docs.djangoproject.com/en/1.10/ref/settings/#templates
8
+  - The ``is_authenticated()`` and ``is_anonymous()`` functions in Django
9
+    OpenStack Auth's ``User`` class are properties when running under Django
10
+    1.10, and no longer take a margin parameter.

Loading…
Cancel
Save