Commit f44f3045 by Troy Sankey Committed by GitHub

Merge pull request #16176 from edx/pwnage101/remove-1.4-shims_PLAT-1424

[WIP] cleanup django 1.4 shims and mentions
parents c63020f9 e94d265f
""" """
Utilities for django models. Utilities for django models.
""" """
import re
import unicodedata
from django.conf import settings from django.conf import settings
from django.dispatch import Signal from django.dispatch import Signal
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django_countries.fields import Country from django_countries.fields import Country
from eventtracking import tracker from eventtracking import tracker
...@@ -171,20 +166,3 @@ def _get_truncated_setting_value(value, max_length=None): ...@@ -171,20 +166,3 @@ def _get_truncated_setting_value(value, max_length=None):
return value[0:max_length], True return value[0:max_length], True
else: else:
return value, False return value, False
# Taken from Django 1.8 source code because it's not supported in 1.4
def slugify(value):
"""Converts value into a string suitable for readable URLs.
Converts to ASCII. Converts spaces to hyphens. Removes characters that
aren't alphanumerics, underscores, or hyphens. Converts to lowercase.
Also strips leading and trailing whitespace.
Args:
value (string): String to slugify.
"""
value = force_unicode(value)
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub(r'[^\w\s-]', '', value).strip().lower()
return mark_safe(re.sub(r'[-\s]+', '-', value))
...@@ -5,7 +5,7 @@ import hashlib ...@@ -5,7 +5,7 @@ import hashlib
import logging import logging
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template.defaultfilters import slugify from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration from badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration
......
...@@ -64,7 +64,7 @@ from student.roles import CourseBetaTesterRole ...@@ -64,7 +64,7 @@ from student.roles import CourseBetaTesterRole
from track import contexts from track import contexts
from util import milestones_helpers from util import milestones_helpers
from util.json_request import JsonResponse from util.json_request import JsonResponse
from util.model_utils import slugify from django.utils.text import slugify
from util.sandboxing import can_execute_unsafe_code, get_python_lib_zip from util.sandboxing import can_execute_unsafe_code, get_python_lib_zip
from xblock_django.user_service import DjangoXBlockUserService from xblock_django.user_service import DjangoXBlockUserService
from xmodule.contentstore.django import contentstore from xmodule.contentstore.django import contentstore
......
...@@ -27,7 +27,7 @@ from lms.djangoapps.teams import TEAM_DISCUSSION_CONTEXT ...@@ -27,7 +27,7 @@ from lms.djangoapps.teams import TEAM_DISCUSSION_CONTEXT
from lms.djangoapps.teams.utils import emit_team_event from lms.djangoapps.teams.utils import emit_team_event
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
from student.models import CourseEnrollment, LanguageField from student.models import CourseEnrollment, LanguageField
from util.model_utils import slugify from django.utils.text import slugify
from .errors import AlreadyOnTeamInCourse, ImmutableMembershipFieldException, NotEnrolledInCourseForTeam from .errors import AlreadyOnTeamInCourse, ImmutableMembershipFieldException, NotEnrolledInCourseForTeam
......
...@@ -12,16 +12,6 @@ from .models import CourseOverview, CourseOverviewImageConfig, CourseOverviewIma ...@@ -12,16 +12,6 @@ from .models import CourseOverview, CourseOverviewImageConfig, CourseOverviewIma
class CourseOverviewAdmin(admin.ModelAdmin): class CourseOverviewAdmin(admin.ModelAdmin):
""" """
Simple, read-only list/search view of Course Overviews. Simple, read-only list/search view of Course Overviews.
The detail view is broken because our primary key for this model are
course keys, which can have a number of chars that break admin URLs.
There's probably a way to make this work properly, but I don't have the
time to investigate. I would normally disable the links by setting
`list_display_links = None`, but that's not a valid value for that
field in Django 1.4. So I'm left with creating a page where the detail
view links are all broken for Split courses. Because I only created
this page to manually test a hotfix, the list view works for this
purpose, and that's all the yak I have time to shave today.
""" """
list_display = [ list_display = [
'id', 'id',
......
...@@ -355,11 +355,10 @@ class CourseOverviewTestCase(ModuleStoreTestCase): ...@@ -355,11 +355,10 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
'openedx.core.djangoapps.content.course_overviews.models.CourseOverview._get_pk_val' 'openedx.core.djangoapps.content.course_overviews.models.CourseOverview._get_pk_val'
) as mock_get_pk_val: ) as mock_get_pk_val:
mock_get_pk_val.return_value = None mock_get_pk_val.return_value = None
# This method was not present in django 1.4. Django 1.8 calls this method if # Django 1.8+ calls this method if _get_pk_val returns None. This method will
# _get_pk_val returns None. This method will return empty str if there is no # return empty str if there is no default value present. So mock it to avoid
# default value present. So mock it to avoid returning the empty str as primary key # returning the empty str as primary key value. Due to empty str, model.save will do
# value. Due to empty str, model.save will do an update instead of insert which is # an update instead of insert which is incorrect and get exception in
# incorrect and get exception in
# openedx.core.djangoapps.xmodule_django.models.OpaqueKeyField.get_prep_value # openedx.core.djangoapps.xmodule_django.models.OpaqueKeyField.get_prep_value
with mock.patch('django.db.models.Field.get_pk_value_on_save') as mock_get_pk_value_on_save: with mock.patch('django.db.models.Field.get_pk_value_on_save') as mock_get_pk_value_on_save:
......
...@@ -33,40 +33,6 @@ TEST_UPLOAD_DT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo=UTC) ...@@ -33,40 +33,6 @@ TEST_UPLOAD_DT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo=UTC)
TEST_UPLOAD_DT2 = datetime.datetime(2003, 1, 9, 15, 43, 01, tzinfo=UTC) TEST_UPLOAD_DT2 = datetime.datetime(2003, 1, 9, 15, 43, 01, tzinfo=UTC)
class PatchedClient(APIClient):
"""
Patch DRF's APIClient to avoid a unicode error on file upload.
Famous last words: This is a *temporary* fix that we should be
able to remove once we upgrade Django past 1.4.
"""
def request(self, *args, **kwargs):
"""Construct an API request. """
# DRF's default test client implementation uses `six.text_type()`
# to convert the CONTENT_TYPE to `unicode`. In Django 1.4,
# this causes a `UnicodeDecodeError` when Django parses a multipart
# upload.
#
# This is the DRF code we're working around:
# https://github.com/tomchristie/django-rest-framework/blob/3.1.3/rest_framework/compat.py#L227
#
# ... and this is the Django code that raises the exception:
#
# https://github.com/django/django/blob/1.4.22/django/http/multipartparser.py#L435
#
# Django unhelpfully swallows the exception, so to the application code
# it appears as though the user didn't send any file data.
#
# This appears to be an issue only with requests constructed in the test
# suite, not with the upload code used in production.
#
if isinstance(kwargs.get("CONTENT_TYPE"), basestring):
kwargs["CONTENT_TYPE"] = str(kwargs["CONTENT_TYPE"])
return super(PatchedClient, self).request(*args, **kwargs)
class ProfileImageEndpointMixin(UserSettingsEventTestMixin): class ProfileImageEndpointMixin(UserSettingsEventTestMixin):
""" """
Base class / shared infrastructure for tests of profile_image "upload" and Base class / shared infrastructure for tests of profile_image "upload" and
...@@ -75,7 +41,6 @@ class ProfileImageEndpointMixin(UserSettingsEventTestMixin): ...@@ -75,7 +41,6 @@ class ProfileImageEndpointMixin(UserSettingsEventTestMixin):
# subclasses should override this with the name of the view under test, as # subclasses should override this with the name of the view under test, as
# per the urls.py configuration. # per the urls.py configuration.
_view_name = None _view_name = None
client_class = PatchedClient
def setUp(self): def setUp(self):
super(ProfileImageEndpointMixin, self).setUp() super(ProfileImageEndpointMixin, self).setUp()
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import datetime import datetime
import json import json
from unittest import skipUnless, SkipTest from unittest import skipUnless
import ddt import ddt
import httpretty import httpretty
...@@ -158,7 +158,7 @@ class RoleTestCase(UserApiTestCase): ...@@ -158,7 +158,7 @@ class RoleTestCase(UserApiTestCase):
self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI)) self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI))
def test_patch_list_not_allowed(self): def test_patch_list_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") self.assertHttpMethodNotAllowed(self.request_with_auth("patch", self.LIST_URI))
def test_delete_list_not_allowed(self): def test_delete_list_not_allowed(self):
self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI)) self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI))
...@@ -243,7 +243,7 @@ class UserViewSetTest(UserApiTestCase): ...@@ -243,7 +243,7 @@ class UserViewSetTest(UserApiTestCase):
self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI)) self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI))
def test_patch_list_not_allowed(self): def test_patch_list_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") self.assertHttpMethodNotAllowed(self.request_with_auth("patch", self.LIST_URI))
def test_delete_list_not_allowed(self): def test_delete_list_not_allowed(self):
self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI)) self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI))
...@@ -310,7 +310,7 @@ class UserViewSetTest(UserApiTestCase): ...@@ -310,7 +310,7 @@ class UserViewSetTest(UserApiTestCase):
self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.detail_uri)) self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.detail_uri))
def test_patch_detail_not_allowed(self): def test_patch_detail_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") self.assertHttpMethodNotAllowed(self.request_with_auth("patch", self.detail_uri))
def test_delete_detail_not_allowed(self): def test_delete_detail_not_allowed(self):
self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.detail_uri)) self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.detail_uri))
...@@ -496,7 +496,7 @@ class PreferenceUsersListViewTest(UserApiTestCase): ...@@ -496,7 +496,7 @@ class PreferenceUsersListViewTest(UserApiTestCase):
self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI)) self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI))
def test_patch_not_allowed(self): def test_patch_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") self.assertHttpMethodNotAllowed(self.request_with_auth("patch", self.LIST_URI))
def test_delete_not_allowed(self): def test_delete_not_allowed(self):
self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI)) self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI))
...@@ -571,7 +571,8 @@ class LoginSessionViewTest(UserAPITestCase): ...@@ -571,7 +571,8 @@ class LoginSessionViewTest(UserAPITestCase):
self.assertHttpMethodNotAllowed(response) self.assertHttpMethodNotAllowed(response)
def test_patch_not_allowed(self): def test_patch_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") response = self.client.patch(self.url)
self.assertHttpMethodNotAllowed(response)
def test_login_form(self): def test_login_form(self):
# Retrieve the login form # Retrieve the login form
...@@ -738,7 +739,8 @@ class PasswordResetViewTest(UserAPITestCase): ...@@ -738,7 +739,8 @@ class PasswordResetViewTest(UserAPITestCase):
self.assertHttpMethodNotAllowed(response) self.assertHttpMethodNotAllowed(response)
def test_patch_not_allowed(self): def test_patch_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") response = self.client.patch(self.url)
self.assertHttpMethodNotAllowed(response)
def test_password_reset_form(self): def test_password_reset_form(self):
# Retrieve the password reset form # Retrieve the password reset form
...@@ -991,7 +993,8 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase): ...@@ -991,7 +993,8 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
self.assertHttpMethodNotAllowed(response) self.assertHttpMethodNotAllowed(response)
def test_patch_not_allowed(self): def test_patch_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch") response = self.client.patch(self.url)
self.assertHttpMethodNotAllowed(response)
def test_register_form_default_fields(self): def test_register_form_default_fields(self):
no_extra_fields_setting = {} no_extra_fields_setting = {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment