diff --git a/common/djangoapps/util/model_utils.py b/common/djangoapps/util/model_utils.py index 5aec1bada0..bc22fb0017 100644 --- a/common/djangoapps/util/model_utils.py +++ b/common/djangoapps/util/model_utils.py @@ -1,13 +1,8 @@ """ Utilities for django models. """ -import re -import unicodedata - from django.conf import settings 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 eventtracking import tracker @@ -171,20 +166,3 @@ def _get_truncated_setting_value(value, max_length=None): return value[0:max_length], True else: 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)) diff --git a/lms/djangoapps/badges/events/course_complete.py b/lms/djangoapps/badges/events/course_complete.py index 24002771ae..7cb9e4986c 100644 --- a/lms/djangoapps/badges/events/course_complete.py +++ b/lms/djangoapps/badges/events/course_complete.py @@ -5,7 +5,7 @@ import hashlib import logging 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 badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 231e960ab3..c4f7a01dfb 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -64,7 +64,7 @@ from student.roles import CourseBetaTesterRole from track import contexts from util import milestones_helpers 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 xblock_django.user_service import DjangoXBlockUserService from xmodule.contentstore.django import contentstore diff --git a/lms/djangoapps/teams/models.py b/lms/djangoapps/teams/models.py index 154f424acd..dd5461263d 100644 --- a/lms/djangoapps/teams/models.py +++ b/lms/djangoapps/teams/models.py @@ -27,7 +27,7 @@ from lms.djangoapps.teams import TEAM_DISCUSSION_CONTEXT from lms.djangoapps.teams.utils import emit_team_event from openedx.core.djangoapps.xmodule_django.models import CourseKeyField from student.models import CourseEnrollment, LanguageField -from util.model_utils import slugify +from django.utils.text import slugify from .errors import AlreadyOnTeamInCourse, ImmutableMembershipFieldException, NotEnrolledInCourseForTeam diff --git a/openedx/core/djangoapps/content/course_overviews/admin.py b/openedx/core/djangoapps/content/course_overviews/admin.py index 7b1c90355a..7cf362b898 100644 --- a/openedx/core/djangoapps/content/course_overviews/admin.py +++ b/openedx/core/djangoapps/content/course_overviews/admin.py @@ -12,16 +12,6 @@ from .models import CourseOverview, CourseOverviewImageConfig, CourseOverviewIma class CourseOverviewAdmin(admin.ModelAdmin): """ 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 = [ 'id', diff --git a/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py b/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py index 92537f08d2..c42f285f77 100644 --- a/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py +++ b/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py @@ -355,11 +355,10 @@ class CourseOverviewTestCase(ModuleStoreTestCase): 'openedx.core.djangoapps.content.course_overviews.models.CourseOverview._get_pk_val' ) as mock_get_pk_val: mock_get_pk_val.return_value = None - # This method was not present in django 1.4. Django 1.8 calls this method if - # _get_pk_val returns None. This method will return empty str if there is no - # default value present. So mock it to avoid returning the empty str as primary key - # value. Due to empty str, model.save will do an update instead of insert which is - # incorrect and get exception in + # Django 1.8+ calls this method if _get_pk_val returns None. This method will + # return empty str if there is no default value present. So mock it to avoid + # returning the empty str as primary key value. Due to empty str, model.save will do + # an update instead of insert which is incorrect and get exception in # 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: diff --git a/openedx/core/djangoapps/profile_images/tests/test_views.py b/openedx/core/djangoapps/profile_images/tests/test_views.py index 9f885a37de..e6f60049a4 100644 --- a/openedx/core/djangoapps/profile_images/tests/test_views.py +++ b/openedx/core/djangoapps/profile_images/tests/test_views.py @@ -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) -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): """ Base class / shared infrastructure for tests of profile_image "upload" and @@ -75,7 +41,6 @@ class ProfileImageEndpointMixin(UserSettingsEventTestMixin): # subclasses should override this with the name of the view under test, as # per the urls.py configuration. _view_name = None - client_class = PatchedClient def setUp(self): super(ProfileImageEndpointMixin, self).setUp() diff --git a/openedx/core/djangoapps/user_api/tests/test_views.py b/openedx/core/djangoapps/user_api/tests/test_views.py index 46964c0d78..d5277b8f33 100644 --- a/openedx/core/djangoapps/user_api/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/tests/test_views.py @@ -2,7 +2,7 @@ import datetime import json -from unittest import skipUnless, SkipTest +from unittest import skipUnless import ddt import httpretty @@ -158,7 +158,7 @@ class RoleTestCase(UserApiTestCase): self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI)) 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): self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI)) @@ -243,7 +243,7 @@ class UserViewSetTest(UserApiTestCase): self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI)) 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): self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI)) @@ -310,7 +310,7 @@ class UserViewSetTest(UserApiTestCase): self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.detail_uri)) 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): self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.detail_uri)) @@ -496,7 +496,7 @@ class PreferenceUsersListViewTest(UserApiTestCase): self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI)) 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): self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI)) @@ -571,7 +571,8 @@ class LoginSessionViewTest(UserAPITestCase): self.assertHttpMethodNotAllowed(response) 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): # Retrieve the login form @@ -738,7 +739,8 @@ class PasswordResetViewTest(UserAPITestCase): self.assertHttpMethodNotAllowed(response) 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): # Retrieve the password reset form @@ -991,7 +993,8 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase): self.assertHttpMethodNotAllowed(response) 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): no_extra_fields_setting = {}