Drop Django <= 1.10 support

After Django 2.0 support, we no longer supports Django 1.10 or older
(Actually Django 1.10 seems to work though).
The current django.VERSION branches are all related to Django 1.10
or older, so we can drop all conditions.

py35dj20 job is now voting.

blueprint django2-support
Change-Id: Iefc0ab1c62c82f2842ec7761a9b981da9351cbd2
This commit is contained in:
Akihiro Motoki 2017-12-17 05:17:43 +09:00
parent 4dd60373dc
commit a72963bdbd
13 changed files with 81 additions and 167 deletions

View File

@ -54,11 +54,11 @@
- project:
check:
jobs:
- horizon-openstack-tox-py35dj20:
voting: false
- horizon-openstack-tox-py35dj20
- horizon-selenium-headless
- horizon-dsvm-tempest-plugin
gate:
jobs:
- horizon-openstack-tox-py35dj20
- horizon-selenium-headless
- horizon-dsvm-tempest-plugin

View File

@ -27,7 +27,6 @@ import inspect
import logging
import os
import django
from django.conf import settings
from django.conf.urls import include
from django.conf.urls import url
@ -58,12 +57,7 @@ def _decorate_urlconf(urlpatterns, decorator, *args, **kwargs):
for pattern in urlpatterns:
if getattr(pattern, 'callback', None):
decorated = decorator(pattern.callback, *args, **kwargs)
if django.VERSION >= (1, 10):
pattern.callback = decorated
else:
# prior to 1.10 callback was a property and we had
# to modify the private attribute behind the property
pattern._callback = decorated
pattern.callback = decorated
if getattr(pattern, 'url_patterns', []):
_decorate_urlconf(pattern.url_patterns, decorator, *args, **kwargs)

View File

@ -10,15 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import django
from django import template
from django.template import defaultfilters
from django.utils import safestring
if django.VERSION >= (1, 9):
register = template.Library()
else:
register = template.base.Library()
register = template.Library()
@register.filter(is_safe=True)

View File

@ -22,7 +22,6 @@ from importlib import import_module
import six
from six import moves
import django
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured
@ -310,10 +309,7 @@ class HorizonTests(BaseHorizonTests):
self.client.logout()
resp = self.client.get(url)
if django.VERSION >= (1, 9):
self.assertRedirects(resp, settings.TESTSERVER + redirect_url)
else:
self.assertRedirects(resp, redirect_url)
self.assertRedirects(resp, settings.TESTSERVER + redirect_url)
# Set SSL settings for test server
settings.SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL',

View File

@ -13,7 +13,6 @@
import uuid
import django
from django.conf import settings
from django.contrib import auth
from django import test
@ -395,10 +394,7 @@ class OpenStackAuthTestsV2(OpenStackAuthTestsMixin, test.TestCase):
response = self.client.get(url, form_data)
if next:
if django.VERSION >= (1, 9):
expected_url = next
else:
expected_url = 'http://testserver%s' % next
expected_url = next
self.assertEqual(response['location'], expected_url)
else:
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
@ -444,10 +440,7 @@ class OpenStackAuthTestsV2(OpenStackAuthTestsMixin, test.TestCase):
response = self.client.get(url, form_data)
if next:
if django.VERSION >= (1, 9):
expected_url = next
else:
expected_url = 'http://testserver%s' % next
expected_url = next
self.assertEqual(response['location'], expected_url)
else:
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
@ -768,10 +761,7 @@ class OpenStackAuthTestsV3(OpenStackAuthTestsMixin,
response = self.client.get(url, form_data)
if next:
if django.VERSION >= (1, 9):
expected_url = next
else:
expected_url = 'http://testserver%s' % next
expected_url = next
self.assertEqual(response['location'], expected_url)
else:
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
@ -816,10 +806,7 @@ class OpenStackAuthTestsV3(OpenStackAuthTestsMixin,
response = self.client.get(url, form_data)
if next:
if django.VERSION >= (1, 9):
expected_url = next
else:
expected_url = 'http://testserver%s' % next
expected_url = next
self.assertEqual(response['location'], expected_url)
else:
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)

View File

@ -17,7 +17,6 @@ import logging
import os
import unittest
import django
from django import http
from django.test.utils import override_settings
from django.urls import reverse
@ -277,14 +276,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
res = self.client.get(reverse('horizon:identity:projects:create'))
self.assertTemplateUsed(res, views.WorkflowView.template_name)
if django.VERSION >= (1, 10):
pattern = ('<input autocomplete="off" class="form-control" '
'id="id_subnet" min="-1" '
'name="subnet" type="number" value="10" required/>')
else:
pattern = ('<input autocomplete="off" class="form-control" '
'id="id_subnet" min="-1" '
'name="subnet" type="number" value="10"/>')
pattern = ('<input autocomplete="off" class="form-control" '
'id="id_subnet" min="-1" '
'name="subnet" type="number" value="10" required/>')
self.assertContains(res, pattern, html=True)
workflow = res.context['workflow']

View File

@ -18,7 +18,6 @@
from socket import timeout as socket_timeout
import django
from django import http
from django.test.utils import override_settings
from django.urls import reverse
@ -238,19 +237,18 @@ class UsersViewTests(test.BaseAdminViewTests):
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
if django.VERSION >= (1, 9):
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
self.mox.ReplayAll()
@ -291,19 +289,18 @@ class UsersViewTests(test.BaseAdminViewTests):
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
if django.VERSION >= (1, 9):
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
self.mox.ReplayAll()
@ -347,19 +344,18 @@ class UsersViewTests(test.BaseAdminViewTests):
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
if django.VERSION >= (1, 9):
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
self.mox.ReplayAll()

View File

@ -1783,18 +1783,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
# NOTE(adriant): Django 1.11 changes the checked syntax to use html5
# "checked" rather than XHTML's "checked='checked'".
if django.VERSION >= (1, 11):
checked_box = (
'<input type="checkbox" name="network" '
'value="82288d84-e0a5-42ac-95be-e6af08727e42" '
'id="id_network_0" checked />'
)
else:
checked_box = (
'<input type="checkbox" name="network" '
'value="82288d84-e0a5-42ac-95be-e6af08727e42" '
'id="id_network_0" checked="checked" />'
)
checked_box = (
'<input type="checkbox" name="network" '
'value="82288d84-e0a5-42ac-95be-e6af08727e42" '
'id="id_network_0" checked />'
)
if only_one_network:
self.assertContains(res, checked_box, html=True)
else:

View File

@ -13,7 +13,6 @@
# under the License.
import copy
import django
from django import http
from django.urls import reverse
@ -590,14 +589,9 @@ class RouterActionTests(RouterMixin, test.TestCase):
self.assertTemplateUsed(res, 'project/routers/update.html')
self.assertContains(res, 'Router Type')
if django.VERSION >= (1, 10):
pattern = ('<input class="form-control" id="id_mode" name="mode" '
'readonly="readonly" type="text" value="distributed" '
'required/>')
else:
pattern = ('<input class="form-control" id="id_mode" name="mode" '
'readonly="readonly" type="text" '
'value="distributed" />')
pattern = ('<input class="form-control" id="id_mode" name="mode" '
'readonly="readonly" type="text" value="distributed" '
'required/>')
self.assertContains(res, pattern, html=True)
self.assertNotContains(res, 'centralized')

View File

@ -21,7 +21,6 @@ import cgi
from mox3.mox import IsA
import six
import django
from django.conf import settings
from django import http
from django.urls import reverse
@ -478,9 +477,7 @@ class SecurityGroupsViewTests(test.TestCase):
sec_group_list = self.security_groups.list()
rule = self.security_group_rules.first()
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
if django.VERSION >= (1, 9):
for i in range(2):
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
@ -503,13 +500,9 @@ class SecurityGroupsViewTests(test.TestCase):
sec_group_list = self.security_groups.list()
rule = self.security_group_rules.first()
for i in range(3):
for i in range(6):
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
if django.VERSION >= (1, 9):
for i in range(3):
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
self.mox.ReplayAll()
@ -559,10 +552,7 @@ class SecurityGroupsViewTests(test.TestCase):
icmp_rule = self.security_group_rules.list()[1]
# Call POST 5 times (*2 if Django >= 1.9)
call_post = 5
if django.VERSION >= (1, 9):
call_post *= 2
call_post = 5 * 2
for i in range(call_post):
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
@ -921,9 +911,7 @@ class SecurityGroupsViewTests(test.TestCase):
sec_group_list = self.security_groups.list()
rule = self.security_group_rules.first()
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
if django.VERSION >= (1, 9):
for i in range(2):
api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)

View File

@ -17,7 +17,6 @@ import copy
import mock
import six
import django
from django.conf import settings
from django.forms import widgets
from django.template.defaultfilters import slugify
@ -616,12 +615,8 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.assertFormError(res, 'form', None,
"The volume size cannot be less than the "
"snapshot size (40GiB)")
if django.VERSION >= (1, 9):
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
else:
self.assertEqual(2, self.mock_volume_type_list.call_count)
self.assertEqual(1, self.mock_volume_type_default.call_count)
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.mock_volume_snapshot_get.assert_called_with(test.IsHttpRequest(),
str(snapshot.id))
@ -788,12 +783,8 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.assertFormError(res, 'form', None, msg)
if django.VERSION >= (1, 9):
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
else:
self.assertEqual(2, self.mock_volume_type_list.call_count)
self.assertEqual(1, self.mock_volume_type_default.call_count)
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_tenant_limit_usages.call_count)
self.mock_image_get.assert_called_with(test.IsHttpRequest(),
@ -835,14 +826,9 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.assertFormError(res, 'form', None,
"The volume size cannot be less than the "
"image minimum disk size (30GiB)")
if django.VERSION >= (1, 9):
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_availability_zone_list.call_count)
else:
self.assertEqual(2, self.mock_volume_type_list.call_count)
self.assertEqual(1, self.mock_volume_type_default.call_count)
self.assertEqual(1, self.mock_availability_zone_list.call_count)
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_availability_zone_list.call_count)
self.mock_image_get.assert_called_with(test.IsHttpRequest(),
str(image.id))
@ -904,16 +890,10 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
' have 20GiB of your quota available.']
self.assertEqual(res.context['form'].errors['__all__'], expected_error)
if django.VERSION >= (1, 9):
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_volume_list.call_count)
self.assertEqual(2, self.mock_availability_zone_list.call_count)
else:
self.assertEqual(2, self.mock_volume_type_list.call_count)
self.assertEqual(1, self.mock_volume_type_default.call_count)
self.assertEqual(1, self.mock_volume_list.call_count)
self.assertEqual(1, self.mock_availability_zone_list.call_count)
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_volume_list.call_count)
self.assertEqual(2, self.mock_availability_zone_list.call_count)
self.assertEqual(2, self.mock_tenant_limit_usages.call_count)
self.mock_volume_snapshot_list.assert_called_with(
@ -963,14 +943,9 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
' volumes.']
self.assertEqual(res.context['form'].errors['__all__'], expected_error)
if django.VERSION >= (1, 9):
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_availability_zone_list.call_count)
else:
self.assertEqual(2, self.mock_volume_type_list.call_count)
self.assertEqual(1, self.mock_volume_type_default.call_count)
self.assertEqual(1, self.mock_availability_zone_list.call_count)
self.assertEqual(3, self.mock_volume_type_list.call_count)
self.assertEqual(2, self.mock_volume_type_default.call_count)
self.assertEqual(2, self.mock_availability_zone_list.call_count)
self.mock_volume_snapshot_list.assert_called_with(
test.IsHttpRequest(), search_opts=SEARCH_OPTS)

View File

@ -25,7 +25,6 @@ import os
import traceback
import unittest
import django
from django.conf import settings
from django.contrib.messages.storage import default_storage
from django.core.handlers import wsgi
@ -330,14 +329,10 @@ class TestCase(horizon_helpers.TestCase):
Asserts that the given response issued a 302 redirect without
processing the view which is redirected to.
"""
if django.VERSION >= (1, 9):
loc = six.text_type(response._headers.get('location', None)[1])
loc = http.urlunquote(loc)
expected_url = http.urlunquote(expected_url)
self.assertEqual(loc, expected_url)
else:
self.assertEqual(response._headers.get('location', None),
('Location', settings.TESTSERVER + expected_url))
loc = six.text_type(response._headers.get('location', None)[1])
loc = http.urlunquote(loc)
expected_url = http.urlunquote(expected_url)
self.assertEqual(loc, expected_url)
self.assertEqual(response.status_code, 302)
def assertNoFormErrors(self, response, context_name="form"):

View File

@ -0,0 +1,6 @@
---
upgrade:
- |
Django 2.0 support is added as experimental.
Support for Django 1.10 or older releases is dropped.
Django 1.11 (LTS) is still the primary supported Django version.