From 26b4e30833b0410d0131c5e7bfa40b6f418ae135 Mon Sep 17 00:00:00 2001 From: Michael Youngstrom <myoungstrom@edx.org> Date: Tue, 5 Jun 2018 14:21:37 -0400 Subject: [PATCH] Remove django 1.8 shim --- .../contentstore/tests/test_contentstore.py | 10 +- .../course_creators/tests/test_admin.py | 8 +- cms/envs/common.py | 11 +- cms/startup.py | 8 - common/djangoapps/student/helpers.py | 10 +- common/djangoapps/student/tests/test_login.py | 9 +- .../third_party_auth/tests/specs/base.py | 19 +- .../tests/specs/test_google.py | 7 +- .../third_party_auth/tests/specs/test_lti.py | 11 +- .../tests/specs/test_testshib.py | 3 +- common/djangoapps/util/tests/test_db.py | 7 - common/test/acceptance/pages/lms/admin.py | 8 +- .../course_api/blocks/tests/test_api.py | 17 +- lms/djangoapps/course_wiki/editors.py | 12 +- lms/djangoapps/course_wiki/tests/tests.py | 7 +- lms/djangoapps/courseware/tests/test_views.py | 17 +- lms/djangoapps/grades/tests/test_tasks.py | 39 +--- .../student_account/test/test_views.py | 9 +- lms/envs/common.py | 10 +- lms/envs/load_test.py | 6 +- lms/startup.py | 7 - openedx/core/djangoapps/api_admin/widgets.py | 12 +- .../djangoapps/cors_csrf/authentication.py | 5 +- .../core/djangoapps/cors_csrf/middleware.py | 9 +- .../cors_csrf/tests/test_middleware.py | 9 +- .../external_auth/tests/test_shib.py | 11 +- .../external_auth/tests/test_ssl.py | 13 +- .../dot_overrides/validators.py | 13 +- openedx/core/djangoapps/theming/storage.py | 166 ------------------ .../management/commands/email_opt_in_list.py | 7 +- openedx/tests/util/__init__.py | 30 ---- requirements/edx-sandbox/base.txt | 1 + requirements/edx-sandbox/shared.txt | 1 + requirements/edx/base.in | 1 - requirements/edx/base.txt | 10 +- requirements/edx/coverage.txt | 1 + requirements/edx/development.txt | 20 +-- requirements/edx/paver.txt | 3 +- requirements/edx/pip-tools.txt | 1 + requirements/edx/testing.txt | 17 +- 40 files changed, 100 insertions(+), 465 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index d5c3bce6e30..c176998c4a5 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -12,11 +12,11 @@ from unittest import SkipTest from uuid import uuid4 import ddt -import django import lxml.html import mock from django.conf import settings from django.contrib.auth.models import User +from django.middleware.csrf import _compare_salted_tokens from django.test import TestCase from django.test.utils import override_settings from edxval.api import create_video, get_videos_for_course @@ -2235,13 +2235,7 @@ class SigninPageTestCase(TestCase): self.assertIsNotNone(csrf_token.value) self.assertIsNotNone(csrf_input_field) - # TODO: Remove Django 1.11 upgrade shim - # SHIM: _compare_salted_tokens was introduced in 1.10. Move the import and use only that branch post-upgrade. - if django.VERSION < (1, 10): - self.assertEqual(csrf_token.value, csrf_input_field.attrib["value"]) - else: - from django.middleware.csrf import _compare_salted_tokens - self.assertTrue(_compare_salted_tokens(csrf_token.value, csrf_input_field.attrib["value"])) + self.assertTrue(_compare_salted_tokens(csrf_token.value, csrf_input_field.attrib["value"])) def _create_course(test, course_key, course_data): diff --git a/cms/djangoapps/course_creators/tests/test_admin.py b/cms/djangoapps/course_creators/tests/test_admin.py index 438b2e6bf80..66a014b6438 100644 --- a/cms/djangoapps/course_creators/tests/test_admin.py +++ b/cms/djangoapps/course_creators/tests/test_admin.py @@ -3,7 +3,6 @@ Tests course_creators.admin.py. """ import mock -import django from django.contrib.admin.sites import AdminSite from django.contrib.auth.models import User from django.core import mail @@ -106,12 +105,7 @@ class CourseCreatorAdminTest(TestCase): # message sent. Admin message will follow. base_num_emails = 1 if expect_sent_to_user else 0 if expect_sent_to_admin: - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Usernames come back as unicode in 1.10+, remove this shim post-upgrade - if django.VERSION < (1, 10): - context = {'user_name': 'test_user', 'user_email': u'test_user+courses@edx.org'} - else: - context = {'user_name': u'test_user', 'user_email': u'test_user+courses@edx.org'} + context = {'user_name': u'test_user', 'user_email': u'test_user+courses@edx.org'} self.assertEquals(base_num_emails + 1, len(mail.outbox), 'Expected admin message to be sent') sent_mail = mail.outbox[base_num_emails] diff --git a/cms/envs/common.py b/cms/envs/common.py index 3b82d90008f..b67f1ac9000 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -46,8 +46,6 @@ import os import sys from datetime import timedelta -import django - import lms.envs.common # Although this module itself may not use these imported variables, other dependent modules may. from lms.envs.common import ( @@ -461,13 +459,6 @@ XQUEUE_INTERFACE = { ################################# Middleware ################################### -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Remove birdcage references post-1.11 upgrade as it is only in place to help during that deployment -if django.VERSION < (1, 9): - _csrf_middleware = 'birdcage.v1_11.csrf.CsrfViewMiddleware' -else: - _csrf_middleware = 'django.middleware.csrf.CsrfViewMiddleware' - MIDDLEWARE_CLASSES = [ 'crum.CurrentRequestUserMiddleware', 'openedx.core.djangoapps.request_cache.middleware.RequestCache', @@ -477,7 +468,7 @@ MIDDLEWARE_CLASSES = [ 'openedx.core.djangoapps.header_control.middleware.HeaderControlMiddleware', 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', - _csrf_middleware, + 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.sites.middleware.CurrentSiteMiddleware', # Allows us to define redirects via Django admin diff --git a/cms/startup.py b/cms/startup.py index a791a3a9536..abf6f7cd139 100644 --- a/cms/startup.py +++ b/cms/startup.py @@ -5,10 +5,7 @@ Module for code that should run during Studio startup (deprecated) import django from django.conf import settings -from openedx.core.djangoapps.monkey_patch import django_db_models_options - # Force settings to run so that the python path is modified - settings.INSTALLED_APPS # pylint: disable=pointless-statement @@ -19,9 +16,4 @@ def run(): NOTE: DO **NOT** add additional code to this method or this file! The Platform Team is moving all startup code to more standard locations using Django best practices. """ - # TODO: Remove Django 1.11 upgrade shim - # SHIM: We should be able to get rid of this monkey patch post-upgrade - if django.VERSION[0] == 1 and django.VERSION[1] < 10: - django_db_models_options.patch() - django.setup() diff --git a/common/djangoapps/student/helpers.py b/common/djangoapps/student/helpers.py index b31651acad5..74c1464195f 100644 --- a/common/djangoapps/student/helpers.py +++ b/common/djangoapps/student/helpers.py @@ -8,7 +8,6 @@ import urllib import urlparse from datetime import datetime -import django from django.conf import settings from django.core.exceptions import PermissionDenied from django.urls import NoReverseMatch, reverse @@ -413,13 +412,8 @@ def create_or_set_user_attribute_created_on_site(user, site): UserAttribute.set_user_attribute(user, 'created_on_site', site.domain) -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Compensate for behavior change of default authentication backend in 1.10 -if django.VERSION < (1, 10): - NEW_USER_AUTH_BACKEND = 'django.contrib.auth.backends.ModelBackend' -else: - # We want to allow inactive users to log in only when their account is first created - NEW_USER_AUTH_BACKEND = 'django.contrib.auth.backends.AllowAllUsersModelBackend' +# We want to allow inactive users to log in only when their account is first created +NEW_USER_AUTH_BACKEND = 'django.contrib.auth.backends.AllowAllUsersModelBackend' # Disable this warning because it doesn't make sense to completely refactor tests to appease Pylint # pylint: disable=logging-format-interpolation diff --git a/common/djangoapps/student/tests/test_login.py b/common/djangoapps/student/tests/test_login.py index 089cbb15af2..6258ad83c21 100644 --- a/common/djangoapps/student/tests/test_login.py +++ b/common/djangoapps/student/tests/test_login.py @@ -24,7 +24,6 @@ from openedx.core.djangoapps.password_policy.compliance import ( NonCompliantPasswordWarning ) from openedx.core.djangolib.testing.utils import CacheIsolationTestCase -from openedx.tests.util import expected_redirect_url from student.tests.factories import RegistrationFactory, UserFactory, UserProfileFactory from student.views import login_oauth_token from third_party_auth.tests.utils import ( @@ -597,7 +596,7 @@ class ExternalAuthShibTest(ModuleStoreTestCase): """ response = self.client.get(reverse('dashboard')) self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], expected_redirect_url('/login?next=/dashboard')) + self.assertEqual(response['Location'], '/login?next=/dashboard') @unittest.skipUnless(settings.FEATURES.get('AUTH_USE_SHIB'), "AUTH_USE_SHIB not set") def test_externalauth_login_required_course_context(self): @@ -608,7 +607,7 @@ class ExternalAuthShibTest(ModuleStoreTestCase): target_url = reverse('courseware', args=[text_type(self.course.id)]) noshib_response = self.client.get(target_url, follow=True, HTTP_ACCEPT="text/html") self.assertEqual(noshib_response.redirect_chain[-1], - (expected_redirect_url('/login?next={url}'.format(url=target_url)), 302)) + ('/login?next={url}'.format(url=target_url), 302)) self.assertContains(noshib_response, (u"Sign in or Register | {platform_name}" .format(platform_name=settings.PLATFORM_NAME))) self.assertEqual(noshib_response.status_code, 200) @@ -623,9 +622,9 @@ class ExternalAuthShibTest(ModuleStoreTestCase): # The 'courseware' page actually causes a redirect itself, so it's not the end of the chain and we # won't test its contents self.assertEqual(shib_response.redirect_chain[-3], - (expected_redirect_url('/shib-login/?next={url}'.format(url=target_url_shib)), 302)) + ('/shib-login/?next={url}'.format(url=target_url_shib), 302)) self.assertEqual(shib_response.redirect_chain[-2], - (expected_redirect_url(target_url_shib), 302)) + (target_url_shib, 302)) self.assertEqual(shib_response.status_code, 200) diff --git a/common/djangoapps/third_party_auth/tests/specs/base.py b/common/djangoapps/third_party_auth/tests/specs/base.py index 2842c56fa04..16d75b91408 100644 --- a/common/djangoapps/third_party_auth/tests/specs/base.py +++ b/common/djangoapps/third_party_auth/tests/specs/base.py @@ -8,7 +8,6 @@ import json import mock from contextlib import contextmanager -import django from django import test from django.contrib import auth from django.contrib.auth import models as auth_models @@ -23,7 +22,6 @@ from social_django import views as social_views from lms.djangoapps.commerce.tests import TEST_API_URL from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory -from openedx.tests.util import expected_redirect_url from student import models as student_models from student import views as student_views from student.tests.factories import UserFactory @@ -68,7 +66,7 @@ class IntegrationTestMixin(object): provider_response = self.do_provider_login(try_login_response['Location']) # We should be redirected to the register screen since this account is not linked to an edX account: self.assertEqual(provider_response.status_code, 302) - self.assertEqual(provider_response['Location'], expected_redirect_url(self.register_page_url, hostname=self.hostname)) + self.assertEqual(provider_response['Location'], self.register_page_url) register_response = self.client.get(self.register_page_url) tpa_context = register_response.context["data"]["third_party_auth"] self.assertEqual(tpa_context["errorMessage"], None) @@ -98,7 +96,7 @@ class IntegrationTestMixin(object): continue_response = self.client.get(tpa_context["finishAuthUrl"]) # And we should be redirected to the dashboard: self.assertEqual(continue_response.status_code, 302) - self.assertEqual(continue_response['Location'], expected_redirect_url(reverse('dashboard'), hostname=self.hostname)) + self.assertEqual(continue_response['Location'], reverse('dashboard')) # Now check that we can login again, whether or not we have yet verified the account: self.client.logout() @@ -119,7 +117,7 @@ class IntegrationTestMixin(object): complete_response = self.do_provider_login(try_login_response['Location']) # We should be redirected to the login screen since this account is not linked to an edX account: self.assertEqual(complete_response.status_code, 302) - self.assertEqual(complete_response['Location'], expected_redirect_url(self.login_page_url, hostname=self.hostname)) + self.assertEqual(complete_response['Location'], self.login_page_url) login_response = self.client.get(self.login_page_url) tpa_context = login_response.context["data"]["third_party_auth"] self.assertEqual(tpa_context["errorMessage"], None) @@ -136,7 +134,7 @@ class IntegrationTestMixin(object): continue_response = self.client.get(tpa_context["finishAuthUrl"]) # And we should be redirected to the dashboard: self.assertEqual(continue_response.status_code, 302) - self.assertEqual(continue_response['Location'], expected_redirect_url(reverse('dashboard'), hostname=self.hostname)) + self.assertEqual(continue_response['Location'], reverse('dashboard')) # Now check that we can login again: self.client.logout() @@ -165,12 +163,7 @@ class IntegrationTestMixin(object): # required to set the login cookie (it sticks around if the main session times out): if not previous_session_timed_out: self.assertEqual(login_response.status_code, 302) - expected_url = expected_redirect_url(self.complete_url, hostname=self.hostname) - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Get rid of this logic post-upgrade - if django.VERSION >= (1, 9): - expected_url = "{}?".format(expected_url) - self.assertEqual(login_response['Location'], expected_url) + self.assertEqual(login_response['Location'], self.complete_url + "?") # And then we should be redirected to the dashboard: login_response = self.client.get(login_response['Location']) self.assertEqual(login_response.status_code, 302) @@ -178,7 +171,7 @@ class IntegrationTestMixin(object): url_expected = reverse('dashboard') else: url_expected = reverse('third_party_inactive_redirect') + '?next=' + reverse('dashboard') - self.assertEqual(login_response['Location'], expected_redirect_url(url_expected, hostname=self.hostname)) + self.assertEqual(login_response['Location'], url_expected) # Now we are logged in: dashboard_response = self.client.get(reverse('dashboard')) self.assertEqual(dashboard_response.status_code, 200) diff --git a/common/djangoapps/third_party_auth/tests/specs/test_google.py b/common/djangoapps/third_party_auth/tests/specs/test_google.py index cb66121dc03..00a4e4cb7ba 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_google.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_google.py @@ -6,7 +6,6 @@ from django.conf import settings from django.urls import reverse import json from mock import patch -from openedx.tests.util import expected_redirect_url from social_core.exceptions import AuthException from student.tests.factories import UserFactory from third_party_auth import pipeline @@ -73,7 +72,7 @@ class GoogleOauth2IntegrationTest(base.Oauth2IntegrationTest): response = self.client.get(complete_url) # This should redirect to the custom login/register form: self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], expected_redirect_url('/auth/custom_auth_entry', hostname='example.none')) + self.assertEqual(response['Location'], '/auth/custom_auth_entry') response = self.client.get(response['Location']) self.assertEqual(response.status_code, 200) @@ -107,7 +106,7 @@ class GoogleOauth2IntegrationTest(base.Oauth2IntegrationTest): # Now our custom login/registration page must resume the pipeline: response = self.client.get(complete_url) self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], expected_redirect_url('/misc/final-destination', hostname='example.none')) + self.assertEqual(response['Location'], '/misc/final-destination') _, strategy = self.get_request_and_strategy() self.assert_social_auth_exists_for_user(created_user, strategy) @@ -134,4 +133,4 @@ class GoogleOauth2IntegrationTest(base.Oauth2IntegrationTest): response = self.client.get(complete_url) # This should redirect to the custom error URL self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], expected_redirect_url('/misc/my-custom-sso-error-page', hostname='example.none')) + self.assertEqual(response['Location'], '/misc/my-custom-sso-error-page') diff --git a/common/djangoapps/third_party_auth/tests/specs/test_lti.py b/common/djangoapps/third_party_auth/tests/specs/test_lti.py index 08390afefb7..dc0fe934f7c 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_lti.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_lti.py @@ -2,12 +2,10 @@ Integration tests for third_party_auth LTI auth providers """ import unittest -import django from django.conf import settings from django.contrib.auth.models import User from django.urls import reverse from oauthlib.oauth1.rfc5849 import Client, SIGNATURE_TYPE_BODY -from openedx.tests.util import expected_redirect_url from third_party_auth.tests import testutil FORM_ENCODED = 'application/x-www-form-urlencoded' @@ -94,7 +92,7 @@ class IntegrationTestLTI(testutil.TestCase): self.assertEqual(continue_response.status_code, 302) self.assertEqual( continue_response['Location'], - expected_redirect_url('/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll') + '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll' ) # Now check that we can login again @@ -108,12 +106,7 @@ class IntegrationTestLTI(testutil.TestCase): login_2_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body) # The user should be redirected to the dashboard self.assertEqual(login_2_response.status_code, 302) - expected_url = expected_redirect_url(LTI_TPA_COMPLETE_URL) - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Get rid of this logic post-upgrade - if django.VERSION >= (1, 9): - expected_url = "{}?".format(expected_url) - self.assertEqual(login_2_response['Location'], expected_url) + self.assertEqual(login_2_response['Location'], LTI_TPA_COMPLETE_URL + "?") continue_2_response = self.client.get(login_2_response['Location']) self.assertEqual(continue_2_response.status_code, 302) self.assertTrue(continue_2_response['Location'].endswith(reverse('dashboard'))) diff --git a/common/djangoapps/third_party_auth/tests/specs/test_testshib.py b/common/djangoapps/third_party_auth/tests/specs/test_testshib.py index 7478ab0a009..8691a986189 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_testshib.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_testshib.py @@ -13,7 +13,6 @@ from social_django.models import UserSocialAuth from testfixtures import LogCapture from unittest import skip -from openedx.tests.util import expected_redirect_url from third_party_auth.saml import log as saml_log, SapSuccessFactorsIdentityProvider from third_party_auth.tasks import fetch_saml_metadata from third_party_auth.tests import testutil @@ -136,7 +135,7 @@ class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin try_login_response = self.client.get(testshib_login_url) # The user should be redirected to back to the login page: self.assertEqual(try_login_response.status_code, 302) - self.assertEqual(try_login_response['Location'], expected_redirect_url(self.login_page_url, hostname=self.hostname)) + self.assertEqual(try_login_response['Location'], self.login_page_url) # When loading the login page, the user will see an error message: response = self.client.get(self.login_page_url) self.assertEqual(response.status_code, 200) diff --git a/common/djangoapps/util/tests/test_db.py b/common/djangoapps/util/tests/test_db.py index 372bf6eae12..b3c3b2dd135 100644 --- a/common/djangoapps/util/tests/test_db.py +++ b/common/djangoapps/util/tests/test_db.py @@ -5,7 +5,6 @@ import time import unittest import ddt -import django import pytest from django.contrib.auth.models import User from django.core.management import call_command @@ -217,7 +216,6 @@ class GenerateIntIdTestCase(TestCase): self.assertIn(int_id, list(set(range(minimum, maximum + 1)) - used_ids)) -@pytest.mark.django111_expected_failure class MigrationTests(TestCase): """ Tests for migrations. @@ -235,11 +233,6 @@ class MigrationTests(TestCase): make a migrationless release that'll require a separate migration release afterwards, this test doesn't fail. """ - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Migrations are known to be needed when actually bumping the Django version number. - if django.VERSION >= (1, 9): - pytest.skip("Migrations are known to be needed for Django 1.9+!") - out = StringIO() call_command('makemigrations', dry_run=True, verbosity=3, stdout=out) output = out.getvalue() diff --git a/common/test/acceptance/pages/lms/admin.py b/common/test/acceptance/pages/lms/admin.py index 6f86ae89c65..214b7cebc3a 100644 --- a/common/test/acceptance/pages/lms/admin.py +++ b/common/test/acceptance/pages/lms/admin.py @@ -1,7 +1,6 @@ """ Pages object for the Django's /admin/ views. """ -import django from bok_choy.page_object import PageObject from common.test.acceptance.pages.lms import BASE_URL @@ -30,12 +29,7 @@ class ChangeUserAdminPage(PageObject): """ Reads the read-only username. """ - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Get rid of this logic post-upgrade - if django.VERSION < (1, 11): - return self.q(css='.field-username p').text[0] - else: - return self.q(css='.field-username .readonly').text[0] + return self.q(css='.field-username .readonly').text[0] @property def first_name_element(self): diff --git a/lms/djangoapps/course_api/blocks/tests/test_api.py b/lms/djangoapps/course_api/blocks/tests/test_api.py index 324b6a1551b..1c03f26d740 100644 --- a/lms/djangoapps/course_api/blocks/tests/test_api.py +++ b/lms/djangoapps/course_api/blocks/tests/test_api.py @@ -5,7 +5,6 @@ Tests for Blocks api.py from itertools import product import ddt -import django from django.test.client import RequestFactory from django.test.utils import override_settings @@ -180,13 +179,7 @@ class TestGetBlocksQueryCounts(TestGetBlocksQueryCountsBase): clear_course_from_cache(course.id) if with_storage_backing: - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Django 1.11 results in a few more SAVEPOINTs due to: - # https://github.com/django/django/commit/d44afd88#diff-5b0dda5eb9a242c15879dc9cd2121379L485 - if django.VERSION >= (1, 11): - num_sql_queries = 16 - else: - num_sql_queries = 14 + num_sql_queries = 16 else: num_sql_queries = 6 @@ -235,13 +228,7 @@ class TestQueryCountsWithIndividualOverrideProvider(TestGetBlocksQueryCountsBase clear_course_from_cache(course.id) if with_storage_backing: - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Django 1.11 results in a few more SAVEPOINTs due to: - # https://github.com/django/django/commit/d44afd88#diff-5b0dda5eb9a242c15879dc9cd2121379L485 - if django.VERSION >= (1, 11): - num_sql_queries = 17 - else: - num_sql_queries = 15 + num_sql_queries = 17 else: num_sql_queries = 7 diff --git a/lms/djangoapps/course_wiki/editors.py b/lms/djangoapps/course_wiki/editors.py index 0b61d035713..ea82427e18e 100644 --- a/lms/djangoapps/course_wiki/editors.py +++ b/lms/djangoapps/course_wiki/editors.py @@ -2,7 +2,6 @@ Support for using the CodeMirror code editor as a wiki content editor. """ -import django from django import forms from django.forms.utils import flatatt from django.template.loader import render_to_string @@ -33,14 +32,9 @@ class CodeMirrorWidget(forms.Widget): if value is None: value = '' - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Compensate for build_attrs() implementation change in 1.11 - if django.VERSION < (1, 11): - final_attrs = self.build_attrs(attrs, name=name) - else: - extra_attrs = attrs.copy() - extra_attrs['name'] = name - final_attrs = self.build_attrs(self.attrs, extra_attrs=extra_attrs) # pylint: disable=redundant-keyword-arg + extra_attrs = attrs.copy() + extra_attrs['name'] = name + final_attrs = self.build_attrs(self.attrs, extra_attrs=extra_attrs) # TODO use the help_text field of edit form instead of rendering a template diff --git a/lms/djangoapps/course_wiki/tests/tests.py b/lms/djangoapps/course_wiki/tests/tests.py index 02a79cb7619..6a060edb115 100644 --- a/lms/djangoapps/course_wiki/tests/tests.py +++ b/lms/djangoapps/course_wiki/tests/tests.py @@ -9,7 +9,6 @@ from six import text_type from courseware.tests.tests import LoginEnrollmentTestCase from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired -from openedx.tests.util import expected_redirect_url from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -58,7 +57,7 @@ class WikiRedirectTestCase(EnterpriseTestConsentRequired, LoginEnrollmentTestCas resp = self.client.get(destination, HTTP_REFERER=referer) self.assertEqual(resp.status_code, 302) - self.assertEqual(resp['Location'], expected_redirect_url(redirected_to)) + self.assertEqual(resp['Location'], redirected_to) # Now we test that the student will be redirected away from that page if the course doesn't exist # We do this in the same test because we want to make sure the redirected_to is constructed correctly @@ -67,7 +66,7 @@ class WikiRedirectTestCase(EnterpriseTestConsentRequired, LoginEnrollmentTestCas resp = self.client.get(bad_course_wiki_page, HTTP_REFERER=referer) self.assertEqual(resp.status_code, 302) - self.assertEqual(resp['Location'], expected_redirect_url(destination)) + self.assertEqual(resp['Location'], destination) @patch.dict("django.conf.settings.FEATURES", {'ALLOW_WIKI_ROOT_ACCESS': False}) def test_wiki_no_root_access(self): @@ -100,7 +99,7 @@ class WikiRedirectTestCase(EnterpriseTestConsentRequired, LoginEnrollmentTestCas ending_location = resp.redirect_chain[-1][0] - self.assertEquals(ending_location, expected_redirect_url(course_wiki_page)) + self.assertEquals(ending_location, course_wiki_page) self.assertEquals(resp.status_code, 200) self.has_course_navigator(resp) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 64f4f7da267..1e3ecf2294e 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -63,7 +63,6 @@ from openedx.core.djangolib.testing.utils import get_mock_request from openedx.core.lib.gating import api as gating_api from openedx.features.course_experience import COURSE_OUTLINE_PAGE_FLAG, UNIFIED_COURSE_TAB_FLAG from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired -from openedx.tests.util import expected_redirect_url from student.models import CourseEnrollment from student.tests.factories import TEST_PASSWORD, AdminFactory, CourseEnrollmentFactory, UserFactory from util.tests.test_date_utils import fake_pgettext, fake_ugettext @@ -106,7 +105,7 @@ class TestJumpTo(ModuleStoreTestCase): course = CourseFactory.create() chapter = ItemFactory.create(category='chapter', parent_location=course.location) section = ItemFactory.create(category='sequential', parent_location=chapter.location) - expected = 'courses/{course_id}/courseware/{chapter_id}/{section_id}/?{activate_block_id}'.format( + expected = '/courses/{course_id}/courseware/{chapter_id}/{section_id}/?{activate_block_id}'.format( course_id=unicode(course.id), chapter_id=chapter.url_name, section_id=section.url_name, @@ -118,7 +117,7 @@ class TestJumpTo(ModuleStoreTestCase): unicode(section.location), ) response = self.client.get(jumpto_url) - self.assertRedirects(response, expected_redirect_url(expected), status_code=302, target_status_code=302) + self.assertRedirects(response, expected, status_code=302, target_status_code=302) def test_jumpto_from_module(self): course = CourseFactory.create() @@ -129,7 +128,7 @@ class TestJumpTo(ModuleStoreTestCase): module1 = ItemFactory.create(category='html', parent_location=vertical1.location) module2 = ItemFactory.create(category='html', parent_location=vertical2.location) - expected = 'courses/{course_id}/courseware/{chapter_id}/{section_id}/1?{activate_block_id}'.format( + expected = '/courses/{course_id}/courseware/{chapter_id}/{section_id}/1?{activate_block_id}'.format( course_id=unicode(course.id), chapter_id=chapter.url_name, section_id=section.url_name, @@ -141,9 +140,9 @@ class TestJumpTo(ModuleStoreTestCase): unicode(module1.location), ) response = self.client.get(jumpto_url) - self.assertRedirects(response, expected_redirect_url(expected), status_code=302, target_status_code=302) + self.assertRedirects(response, expected, status_code=302, target_status_code=302) - expected = 'courses/{course_id}/courseware/{chapter_id}/{section_id}/2?{activate_block_id}'.format( + expected = '/courses/{course_id}/courseware/{chapter_id}/{section_id}/2?{activate_block_id}'.format( course_id=unicode(course.id), chapter_id=chapter.url_name, section_id=section.url_name, @@ -155,7 +154,7 @@ class TestJumpTo(ModuleStoreTestCase): unicode(module2.location), ) response = self.client.get(jumpto_url) - self.assertRedirects(response, expected_redirect_url(expected), status_code=302, target_status_code=302) + self.assertRedirects(response, expected, status_code=302, target_status_code=302) def test_jumpto_from_nested_module(self): course = CourseFactory.create() @@ -171,7 +170,7 @@ class TestJumpTo(ModuleStoreTestCase): # internal position of module2 will be 1_2 (2nd item withing 1st item) - expected = 'courses/{course_id}/courseware/{chapter_id}/{section_id}/1?{activate_block_id}'.format( + expected = '/courses/{course_id}/courseware/{chapter_id}/{section_id}/1?{activate_block_id}'.format( course_id=unicode(course.id), chapter_id=chapter.url_name, section_id=section.url_name, @@ -183,7 +182,7 @@ class TestJumpTo(ModuleStoreTestCase): unicode(module2.location), ) response = self.client.get(jumpto_url) - self.assertRedirects(response, expected_redirect_url(expected), status_code=302, target_status_code=302) + self.assertRedirects(response, expected, status_code=302, target_status_code=302) def test_jumpto_id_invalid_location(self): location = BlockUsageLocator(CourseLocator('edX', 'toy', 'NoSuchPlace', deprecated=True), diff --git a/lms/djangoapps/grades/tests/test_tasks.py b/lms/djangoapps/grades/tests/test_tasks.py index 95f799fa603..c59c4618a70 100644 --- a/lms/djangoapps/grades/tests/test_tasks.py +++ b/lms/djangoapps/grades/tests/test_tasks.py @@ -10,7 +10,6 @@ from datetime import datetime, timedelta import ddt import pytz import six -import django from django.conf import settings from django.db.utils import IntegrityError from mock import MagicMock, patch @@ -111,28 +110,6 @@ class HasCourseWithProblemsMixin(object): # pylint: enable=attribute-defined-outside-init,no-member -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Django 1.11 results in a few more SAVEPOINTs due to: -# https://github.com/django/django/commit/d44afd88#diff-5b0dda5eb9a242c15879dc9cd2121379L485 -# Get rid of this logic post-upgrade. -def _recalc_expected_query_counts(): - if django.VERSION >= (1, 11): - return 27 - else: - return 23 - - -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Django 1.11 results in a few more SAVEPOINTs due to: -# https://github.com/django/django/commit/d44afd88#diff-5b0dda5eb9a242c15879dc9cd2121379L485 -# Get rid of this logic post-upgrade. -def _recalc_persistent_expected_query_counts(): - if django.VERSION >= (1, 11): - return 28 - else: - return 24 - - @patch.dict(settings.FEATURES, {'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS': False}) @ddt.ddt class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTestCase): @@ -191,10 +168,10 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest self.assertEquals(mock_block_structure_create.call_count, 1) @ddt.data( - (ModuleStoreEnum.Type.mongo, 1, _recalc_expected_query_counts(), True), - (ModuleStoreEnum.Type.mongo, 1, _recalc_expected_query_counts(), False), - (ModuleStoreEnum.Type.split, 3, _recalc_expected_query_counts(), True), - (ModuleStoreEnum.Type.split, 3, _recalc_expected_query_counts(), False), + (ModuleStoreEnum.Type.mongo, 1, 27, True), + (ModuleStoreEnum.Type.mongo, 1, 27, False), + (ModuleStoreEnum.Type.split, 3, 27, True), + (ModuleStoreEnum.Type.split, 3, 27, False), ) @ddt.unpack def test_query_counts(self, default_store, num_mongo_calls, num_sql_calls, create_multiple_subsections): @@ -206,8 +183,8 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest self._apply_recalculate_subsection_grade() @ddt.data( - (ModuleStoreEnum.Type.mongo, 1, _recalc_expected_query_counts()), - (ModuleStoreEnum.Type.split, 3, _recalc_expected_query_counts()), + (ModuleStoreEnum.Type.mongo, 1, 27), + (ModuleStoreEnum.Type.split, 3, 27), ) @ddt.unpack def test_query_counts_dont_change_with_more_content(self, default_store, num_mongo_calls, num_sql_calls): @@ -267,8 +244,8 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest self.assertEqual(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0) @ddt.data( - (ModuleStoreEnum.Type.mongo, 1, _recalc_persistent_expected_query_counts()), - (ModuleStoreEnum.Type.split, 3, _recalc_persistent_expected_query_counts()), + (ModuleStoreEnum.Type.mongo, 1, 28), + (ModuleStoreEnum.Type.split, 3, 28), ) @ddt.unpack def test_persistent_grades_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries): diff --git a/lms/djangoapps/student_account/test/test_views.py b/lms/djangoapps/student_account/test/test_views.py index 30b69f69835..b078ebf208d 100644 --- a/lms/djangoapps/student_account/test/test_views.py +++ b/lms/djangoapps/student_account/test/test_views.py @@ -47,7 +47,6 @@ from openedx.core.djangoapps.user_api.accounts.api import activate_account, crea from openedx.core.djangolib.js_utils import dump_js_escaped_json from openedx.core.djangolib.markup import HTML, Text from openedx.core.djangolib.testing.utils import CacheIsolationTestCase -from openedx.tests.util import expected_redirect_url from student.tests.factories import UserFactory from student_account.views import account_settings_context, get_user_orders from third_party_auth.tests.testutil import ThirdPartyAuthTestMixin, simulate_running_pipeline @@ -605,9 +604,11 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi self.google_provider.save() params = [("next", "/courses/something/?tpa_hint=oa2-google-oauth2")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") + expected_url = '/auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses'\ + '%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry) self.assertRedirects( response, - expected_redirect_url('auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry)), + expected_url, target_status_code=302 ) @@ -649,9 +650,11 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi self.google_provider.save() params = [("next", "/courses/something/")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") + expected_url = '/auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses'\ + '%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry) self.assertRedirects( response, - expected_redirect_url('auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry)), + expected_url, target_status_code=302 ) diff --git a/lms/envs/common.py b/lms/envs/common.py index 338fbe798b7..86c4a29f665 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -33,7 +33,6 @@ import imp import sys import os -import django from path import Path as path from django.utils.translation import ugettext_lazy as _ @@ -1216,13 +1215,6 @@ CREDIT_NOTIFICATION_CACHE_TIMEOUT = 5 * 60 * 60 ################################# Middleware ################################### -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Remove birdcage references post-1.11 upgrade as it is only in place to help during that deployment -if django.VERSION < (1, 9): - _csrf_middleware = 'birdcage.v1_11.csrf.CsrfViewMiddleware' -else: - _csrf_middleware = 'django.middleware.csrf.CsrfViewMiddleware' - MIDDLEWARE_CLASSES = [ 'crum.CurrentRequestUserMiddleware', @@ -1264,7 +1256,7 @@ MIDDLEWARE_CLASSES = [ 'corsheaders.middleware.CorsMiddleware', 'openedx.core.djangoapps.cors_csrf.middleware.CorsCSRFMiddleware', 'openedx.core.djangoapps.cors_csrf.middleware.CsrfCrossDomainCookieMiddleware', - _csrf_middleware, + 'django.middleware.csrf.CsrfViewMiddleware', 'splash.middleware.SplashMiddleware', diff --git a/lms/envs/load_test.py b/lms/envs/load_test.py index cfc90add27d..7b7e7df4051 100644 --- a/lms/envs/load_test.py +++ b/lms/envs/load_test.py @@ -8,14 +8,10 @@ Settings for load testing. from .aws import * -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Remove birdcage references post-1.11 upgrade as it is only in place to help during that deployment - # Disable CSRF for load testing EXCLUDE_CSRF = lambda elem: elem not in [ 'django.template.context_processors.csrf', - 'django.middleware.csrf.CsrfViewMiddleware', - 'birdcage.v1_11.csrf.CsrfViewMiddleware' + 'django.middleware.csrf.CsrfViewMiddleware' ] DEFAULT_TEMPLATE_ENGINE['OPTIONS']['context_processors'] = filter( EXCLUDE_CSRF, DEFAULT_TEMPLATE_ENGINE['OPTIONS']['context_processors'] diff --git a/lms/startup.py b/lms/startup.py index f1326f0a497..a5255f53798 100644 --- a/lms/startup.py +++ b/lms/startup.py @@ -5,8 +5,6 @@ Module for code that should run during LMS startup (deprecated) import django from django.conf import settings -from openedx.core.djangoapps.monkey_patch import django_db_models_options - # Force settings to run so that the python path is modified settings.INSTALLED_APPS # pylint: disable=pointless-statement @@ -18,9 +16,4 @@ def run(): NOTE: DO **NOT** add additional code to this method or this file! The Platform Team is moving all startup code to more standard locations using Django best practices. """ - # TODO: Remove Django 1.11 upgrade shim - # SHIM: We should be able to get rid of this monkey patch post-upgrade - if django.VERSION[0] == 1 and django.VERSION[1] < 10: - django_db_models_options.patch() - django.setup() diff --git a/openedx/core/djangoapps/api_admin/widgets.py b/openedx/core/djangoapps/api_admin/widgets.py index ae50044af41..0bef4dd37a3 100644 --- a/openedx/core/djangoapps/api_admin/widgets.py +++ b/openedx/core/djangoapps/api_admin/widgets.py @@ -1,6 +1,5 @@ """ Form widget classes """ -import django from django.conf import settings from django.urls import reverse from django.forms.utils import flatatt @@ -16,14 +15,9 @@ class TermsOfServiceCheckboxInput(CheckboxInput): """ Renders a checkbox with a label linking to the terms of service. """ def render(self, name, value, attrs=None): - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Compensate for behavior change of default authentication backend in 1.10 - if django.VERSION < (1, 11): - final_attrs = self.build_attrs(attrs, type='checkbox', name=name) - else: - extra_attrs = attrs.copy() - extra_attrs.update({'type': 'checkbox', 'name': name}) - final_attrs = self.build_attrs(self.attrs, extra_attrs=extra_attrs) # pylint: disable=redundant-keyword-arg + extra_attrs = attrs.copy() + extra_attrs.update({'type': 'checkbox', 'name': name}) + final_attrs = self.build_attrs(self.attrs, extra_attrs=extra_attrs) if self.check_test(value): final_attrs['checked'] = 'checked' diff --git a/openedx/core/djangoapps/cors_csrf/authentication.py b/openedx/core/djangoapps/cors_csrf/authentication.py index 91dc5098a2d..f4f2471932c 100644 --- a/openedx/core/djangoapps/cors_csrf/authentication.py +++ b/openedx/core/djangoapps/cors_csrf/authentication.py @@ -24,11 +24,8 @@ class SessionAuthenticationCrossDomainCsrf(authentication.SessionAuthentication) Since this subclass overrides only the `enforce_csrf()` method, it can be mixed in with other `SessionAuthentication` subclasses. """ - # TODO: Remove Django 1.11 upgrade shim - # SHIM: Call new process_request in Django 1.11 to process CSRF token in cookie. def _process_enforce_csrf(self, request): - if django.VERSION >= (1, 11): - CsrfViewMiddleware().process_request(request) + CsrfViewMiddleware().process_request(request) return super(SessionAuthenticationCrossDomainCsrf, self).enforce_csrf(request) def enforce_csrf(self, request): diff --git a/openedx/core/djangoapps/cors_csrf/middleware.py b/openedx/core/djangoapps/cors_csrf/middleware.py index 1f3c8ee3653..7478d542874 100644 --- a/openedx/core/djangoapps/cors_csrf/middleware.py +++ b/openedx/core/djangoapps/cors_csrf/middleware.py @@ -44,19 +44,12 @@ CSRF cookie. import logging -import django from django.conf import settings from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed +from django.middleware.csrf import CsrfViewMiddleware from .helpers import is_cross_domain_request_allowed, skip_cross_domain_referer_check -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Remove birdcage references post-1.11 upgrade as it is only in place to help during that deployment -if django.VERSION < (1, 9): - from birdcage.v1_11.csrf import CsrfViewMiddleware -else: - from django.middleware.csrf import CsrfViewMiddleware - log = logging.getLogger(__name__) diff --git a/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py b/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py index 7c30b8ce334..9c6480ba92c 100644 --- a/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py +++ b/openedx/core/djangoapps/cors_csrf/tests/test_middleware.py @@ -5,18 +5,11 @@ Tests for the CORS CSRF middleware from mock import patch, Mock import ddt -import django from django.test import TestCase from django.test.utils import override_settings from django.core.exceptions import MiddlewareNotUsed, ImproperlyConfigured from django.http import HttpResponse - -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Remove birdcage references post-1.11 upgrade as it is only in place to help during that deployment -if django.VERSION < (1, 9): - from birdcage.v1_11.csrf import CsrfViewMiddleware -else: - from django.middleware.csrf import CsrfViewMiddleware +from django.middleware.csrf import CsrfViewMiddleware from ..middleware import CorsCSRFMiddleware, CsrfCrossDomainCookieMiddleware diff --git a/openedx/core/djangoapps/external_auth/tests/test_shib.py b/openedx/core/djangoapps/external_auth/tests/test_shib.py index d9ed8d86203..c89bbfdbc59 100644 --- a/openedx/core/djangoapps/external_auth/tests/test_shib.py +++ b/openedx/core/djangoapps/external_auth/tests/test_shib.py @@ -8,7 +8,6 @@ import unittest from importlib import import_module from urllib import urlencode -import django import pytest from ddt import ddt, data from django.conf import settings @@ -23,7 +22,6 @@ from openedx.core.djangoapps.external_auth.views import ( shib_login, course_specific_login, course_specific_register, _flatten_to_ascii ) from openedx.core.djangoapps.user_api import accounts as accounts_settings -from openedx.tests.util import expected_redirect_url from mock import patch from nose.plugins.attrib import attr from six import text_type @@ -369,12 +367,7 @@ class ShibSPTest(CacheIsolationTestCase): if len(external_name.strip()) < accounts_settings.NAME_MIN_LENGTH: self.assertEqual(profile.name, postvars['name']) else: - expected_name = external_name - # TODO: Remove Django 1.11 upgrade shim - # SHIM: form character fields strip leading and trailing whitespace by default in Django 1.9+ - if django.VERSION >= (1, 9): - expected_name = expected_name.strip() - self.assertEqual(profile.name, expected_name) + self.assertEqual(profile.name, external_name.strip()) self.assertNotIn(u';', profile.name) else: self.assertEqual(profile.name, self.client.session['ExternalAuthMap'].external_name) @@ -586,7 +579,7 @@ class ShibSPTestModifiedCourseware(ModuleStoreTestCase): # successful login is a redirect to the URL that handles auto-enrollment self.assertEqual(response.status_code, 302) self.assertEqual(response['location'], - expected_redirect_url('/account/finish_auth?{}'.format(urlencode(params)))) + '/account/finish_auth?{}'.format(urlencode(params))) class ShibUtilFnTest(TestCase): diff --git a/openedx/core/djangoapps/external_auth/tests/test_ssl.py b/openedx/core/djangoapps/external_auth/tests/test_ssl.py index de5454ee935..056211ed640 100644 --- a/openedx/core/djangoapps/external_auth/tests/test_ssl.py +++ b/openedx/core/djangoapps/external_auth/tests/test_ssl.py @@ -20,7 +20,6 @@ from openedx.core.djangoapps.external_auth.models import ExternalAuthMap import openedx.core.djangoapps.external_auth.views as external_auth_views from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory from openedx.core.djangolib.testing.utils import skip_unless_cms, skip_unless_lms -from openedx.tests.util import expected_redirect_url from student.models import CourseEnrollment from student.roles import CourseStaffRole from student.tests.factories import UserFactory @@ -183,7 +182,7 @@ class SSLClientTest(ModuleStoreTestCase): response = self.client.get( reverse('dashboard'), follow=True, SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)) - self.assertEquals((expected_redirect_url('/dashboard'), 302), + self.assertEquals(('/dashboard', 302), response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) @@ -197,7 +196,7 @@ class SSLClientTest(ModuleStoreTestCase): response = self.client.get( reverse('register_user'), follow=True, SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)) - self.assertEquals((expected_redirect_url('/dashboard'), 302), + self.assertEquals(('/dashboard', 302), response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) @@ -237,7 +236,7 @@ class SSLClientTest(ModuleStoreTestCase): response = self.client.get( reverse('signin_user'), follow=True, SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)) - self.assertEquals((expected_redirect_url('/dashboard'), 302), + self.assertEquals(('/dashboard', 302), response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) @@ -360,7 +359,7 @@ class SSLClientTest(ModuleStoreTestCase): SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL), HTTP_ACCEPT='text/html' ) - self.assertEqual((expected_redirect_url(course_private_url), 302), + self.assertEqual((course_private_url, 302), response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) @@ -392,7 +391,7 @@ class SSLClientTest(ModuleStoreTestCase): SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL), HTTP_ACCEPT='text/html' ) - self.assertEqual((expected_redirect_url(course_private_url), 302), + self.assertEqual((course_private_url, 302), response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) @@ -410,7 +409,7 @@ class SSLClientTest(ModuleStoreTestCase): response = self.client.get( reverse('dashboard'), follow=True, SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)) - self.assertEquals((expected_redirect_url('/dashboard'), 302), + self.assertEquals(('/dashboard', 302), response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) response = self.client.get( diff --git a/openedx/core/djangoapps/oauth_dispatch/dot_overrides/validators.py b/openedx/core/djangoapps/oauth_dispatch/dot_overrides/validators.py index c77d9924a16..a44337a789b 100644 --- a/openedx/core/djangoapps/oauth_dispatch/dot_overrides/validators.py +++ b/openedx/core/djangoapps/oauth_dispatch/dot_overrides/validators.py @@ -5,8 +5,8 @@ from __future__ import unicode_literals from datetime import datetime -import django from django.contrib.auth import authenticate, get_user_model +from django.contrib.auth.backends import AllowAllUsersModelBackend as UserModelBackend from django.db.models.signals import pre_save from django.dispatch import receiver from oauth2_provider.models import AccessToken @@ -31,17 +31,6 @@ def on_access_token_presave(sender, instance, *args, **kwargs): # pylint: disab RestrictedApplication.set_access_token_as_expired(instance) -# TODO: Remove Django 1.11 upgrade shim -# SHIM: Allow users that are inactive to still authenticate while keeping rate-limiting functionality. -if django.VERSION < (1, 10): - # Old backend which allowed inactive users to authenticate prior to Django 1.10. - from django.contrib.auth.backends import ModelBackend as UserModelBackend -else: - # Django 1.10+ ModelBackend disallows inactive users from authenticating, so instead we use - # AllowAllUsersModelBackend which is the closest alternative. - from django.contrib.auth.backends import AllowAllUsersModelBackend as UserModelBackend - - class EdxRateLimitedAllowAllUsersModelBackend(RateLimitMixin, UserModelBackend): """ Authentication backend needed to incorporate rate limiting of login attempts - but also diff --git a/openedx/core/djangoapps/theming/storage.py b/openedx/core/djangoapps/theming/storage.py index 86bcec667ca..e0b566210a0 100644 --- a/openedx/core/djangoapps/theming/storage.py +++ b/openedx/core/djangoapps/theming/storage.py @@ -6,7 +6,6 @@ import os.path import posixpath import re -import django from django.conf import settings from django.contrib.staticfiles.finders import find from django.contrib.staticfiles.storage import CachedFilesMixin, StaticFilesStorage @@ -171,24 +170,6 @@ class ThemeCachedFilesMixin(CachedFilesMixin): return asset_name - # TODO: Remove Django 1.11 upgrade shim - # SHIM: This override method modifies the name argument to contain a theme - # prefix when Django < 1.11. In Django >= 1.11, asset name processing is - # done in the _url function, so this method becomes a no-op passthrough. - # After the 1.11 upgrade, delete this method. - def url(self, name, force=False): - """ - This override method serves a similar function to _url, but this is - needed for Django < 1.11. - """ - if django.VERSION < (1, 11): - processed_asset_name = self._processed_asset_name(name) - return super(ThemeCachedFilesMixin, self).url(processed_asset_name, force) - else: - # Passthrough directly to the function we are overriding. _url in - # Django 1.11+ will take care of processing the asset name. - return super(ThemeCachedFilesMixin, self).url(name, force) - def _url(self, hashed_name_func, name, force=False, hashed_files=None): """ This override method swaps out `name` with a processed version. @@ -198,153 +179,6 @@ class ThemeCachedFilesMixin(CachedFilesMixin): processed_asset_name = self._processed_asset_name(name) return super(ThemeCachedFilesMixin, self)._url(hashed_name_func, processed_asset_name, force, hashed_files) - # TODO: Remove Django 1.11 upgrade shim - # SHIM: This method implements url_converter for Django < 1.11. - # After the 1.11 upgrade, delete this method. - def _url_converter__lt_111(self, name, template=None): - """ - This is an override of url_converter from CachedFilesMixin. - - There are two lines commented out in order to make the converter method - return absolute urls instead of relative urls. This behavior is - necessary for theme overrides, as we get 404 on assets with relative - urls on a themed site. - """ - if template is None: - template = self.default_template - - def converter(matchobj): - """ - Converts the matched URL depending on the parent level (`..`) - and returns the normalized and hashed URL using the url method - of the storage. - """ - matched, url = matchobj.groups() - # Completely ignore http(s) prefixed URLs, - # fragments and data-uri URLs - if url.startswith(('#', 'http:', 'https:', 'data:', '//')): - return matched - name_parts = name.split(os.sep) - # Using posix normpath here to remove duplicates - url = posixpath.normpath(url) - url_parts = url.split('/') - parent_level, sub_level = url.count('..'), url.count('/') - if url.startswith('/'): - sub_level -= 1 - url_parts = url_parts[1:] - if parent_level or not url.startswith('/'): - start, end = parent_level + 1, parent_level - else: - if sub_level: - if sub_level == 1: - parent_level -= 1 - start, end = parent_level, 1 - else: - start, end = 1, sub_level - 1 - joined_result = '/'.join(name_parts[:-start] + url_parts[end:]) - hashed_url = self.url(unquote(joined_result), force=True) - - # NOTE: - # following two lines are commented out so that absolute urls are used instead of relative urls - # to make themed assets work correctly. - # - # The lines are commented and not removed to make future django upgrade easier and - # show exactly what is changed in this method override - # - # file_name = hashed_url.split('/')[-1:] - # relative_url = '/'.join(url.split('/')[:-1] + file_name) - - # Return the hashed version to the file - return template % unquote(hashed_url) - - return converter - - # TODO: Remove Django 1.11 upgrade shim - # SHIM: This method implements url_converter for Django >= 1.11. - # After the 1.11 upgrade, rename this method to url_converter. - def _url_converter__gte_111(self, name, hashed_files, template=None): - """ - This is an override of url_converter from CachedFilesMixin. - - It changes one line near the end of the method (see the NOTE) in order - to return absolute urls instead of relative urls. This behavior is - necessary for theme overrides, as we get 404 on assets with relative - urls on a themed site. - """ - if template is None: - template = self.default_template - - def converter(matchobj): - """ - Convert the matched URL to a normalized and hashed URL. - This requires figuring out which files the matched URL resolves - to and calling the url() method of the storage. - """ - matched, url = matchobj.groups() - - # Ignore absolute/protocol-relative and data-uri URLs. - if re.match(r'^[a-z]+:', url): - return matched - - # Ignore absolute URLs that don't point to a static file (dynamic - # CSS / JS?). Note that STATIC_URL cannot be empty. - if url.startswith('/') and not url.startswith(settings.STATIC_URL): - return matched - - # Strip off the fragment so a path-like fragment won't interfere. - url_path, fragment = urldefrag(url) - - if url_path.startswith('/'): - # Otherwise the condition above would have returned prematurely. - assert url_path.startswith(settings.STATIC_URL) - target_name = url_path[len(settings.STATIC_URL):] - else: - # We're using the posixpath module to mix paths and URLs conveniently. - source_name = name if os.sep == '/' else name.replace(os.sep, '/') - target_name = posixpath.join(posixpath.dirname(source_name), url_path) - - # Determine the hashed name of the target file with the storage backend. - hashed_url = self._url( - self._stored_name, unquote(target_name), - force=True, hashed_files=hashed_files, - ) - - # NOTE: - # The line below was commented out so that absolute urls are used instead of relative urls to make themed - # assets work correctly. - # - # The line is commented and not removed to make future django upgrade easier and show exactly what is - # changed in this method override - # - #transformed_url = '/'.join(url_path.split('/')[:-1] + hashed_url.split('/')[-1:]) - transformed_url = hashed_url # This line was added. - - # Restore the fragment that was stripped off earlier. - if fragment: - transformed_url += ('?#' if '?#' in url else '#') + fragment - - # Return the hashed version to the file - return template % unquote(transformed_url) - - return converter - - # TODO: Remove Django 1.11 upgrade shim - # SHIM: This method switches the implementation of url_converter according - # to the Django version. After the 1.11 upgrade, do these things: - # - # 1. delete _url_converter__lt_111. - # 2. delete url_converter (below). - # 3. rename _url_converter__gte_111 to url_converter. - def url_converter(self, *args, **kwargs): - """ - An implementation selector for the url_converter method. This is in - place only for the Django 1.11 upgrade. - """ - if django.VERSION < (1, 11): - return self._url_converter__lt_111(*args, **kwargs) - else: - return self._url_converter__gte_111(*args, **kwargs) - class ThemePipelineMixin(PipelineMixin): """ diff --git a/openedx/core/djangoapps/user_api/management/commands/email_opt_in_list.py b/openedx/core/djangoapps/user_api/management/commands/email_opt_in_list.py index 0a2bc14f8fe..c9ed29c998d 100644 --- a/openedx/core/djangoapps/user_api/management/commands/email_opt_in_list.py +++ b/openedx/core/djangoapps/user_api/management/commands/email_opt_in_list.py @@ -246,12 +246,7 @@ class Command(BaseCommand): user_id, username, email, full_name, course_id, is_opted_in, pref_set_datetime = row if pref_set_datetime: - # TODO: Remove Django 1.11 upgrade shim - # SHIM: pref_set_datetime.tzinfo should always be None here after the 1.11 upgrade - # As of Django 1.9 datetimes returned from raw sql queries are no longer coerced to being tz aware - # so we correct for that here. - if pref_set_datetime.tzinfo is None or pref_set_datetime.tzinfo.utcoffset(pref_set_datetime) is None: - pref_set_datetime = timezone.make_aware(pref_set_datetime, timezone.utc) + pref_set_datetime = timezone.make_aware(pref_set_datetime, timezone.utc) else: pref_set_datetime = self.DEFAULT_DATETIME_STR diff --git a/openedx/tests/util/__init__.py b/openedx/tests/util/__init__.py index 0db3fb023f8..e69de29bb2d 100644 --- a/openedx/tests/util/__init__.py +++ b/openedx/tests/util/__init__.py @@ -1,30 +0,0 @@ -""" -Utilities for Open edX unit tests. -""" -from __future__ import absolute_import, unicode_literals - -import django - - -# TODO: Remove Django 1.11 upgrade shim -# SHIM: We should be able to get rid of this utility post-upgrade -def expected_redirect_url(relative_url, hostname='testserver'): - """ - Get the expected redirect URL for the current Django version and the - given relative URL: - - * Django 1.8 and earlier redirect URLs beginning with a slash to absolute - URLs, later versions redirect to relative ones. - * Django 1.8 and earlier leave URLs without a leading slash alone, later - versions prepend the missing slash. - """ - if django.VERSION < (1, 9): - if relative_url.startswith('/'): - return 'http://{}{}'.format(hostname, relative_url) - else: - return relative_url - else: - if relative_url.startswith('/'): - return relative_url - else: - return '/{}'.format(relative_url) diff --git a/requirements/edx-sandbox/base.txt b/requirements/edx-sandbox/base.txt index 43115f056f2..6ec232c40fb 100644 --- a/requirements/edx-sandbox/base.txt +++ b/requirements/edx-sandbox/base.txt @@ -4,6 +4,7 @@ # # make upgrade # + common/lib/calc common/lib/chem common/lib/sandbox-packages diff --git a/requirements/edx-sandbox/shared.txt b/requirements/edx-sandbox/shared.txt index 7fb61cce4dc..e9f57b37502 100644 --- a/requirements/edx-sandbox/shared.txt +++ b/requirements/edx-sandbox/shared.txt @@ -4,6 +4,7 @@ # # make upgrade # + -e common/lib/calc -e common/lib/chem -e common/lib/sandbox-packages diff --git a/requirements/edx/base.in b/requirements/edx/base.in index 575f37f83c1..d62719ccf55 100644 --- a/requirements/edx/base.in +++ b/requirements/edx/base.in @@ -35,7 +35,6 @@ ddt==0.8.0 # via xblock-drag-and-drop-v2 (which probabl defusedxml==0.4.1 # XML bomb protection for common XML parsers Django==1.11.13 # Web application framework django-babel-underscore # underscore template extractor for django-babel (internationalization utilities) -django-birdcage # CSRF token forwards compatibility for the Django 1.11 upgrade; can be removed after that django-config-models==0.1.8 # Configuration models for Django allowing config management with auditing django-cors-headers==2.1.0 # Used to allow to configure CORS headers for cross-domain requests django-countries==4.6.1 # Country data for Django forms and model fields diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 595c4756309..41473d9f900 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -4,6 +4,7 @@ # # make upgrade # + -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock -e common/lib/calc -e common/lib/capa @@ -69,7 +70,6 @@ defusedxml==0.4.1 django-appconf==1.0.2 # via django-statici18n django-babel-underscore==0.5.2 django-babel==0.6.2 # via django-babel-underscore -django-birdcage==1.0.0 django-braces==1.13.0 # via django-oauth-toolkit django-classy-tags==0.8.0 # via django-sekizai django-config-models==0.1.8 @@ -93,7 +93,7 @@ django-require==1.0.11 django-rest-swagger==2.2.0 django-sekizai==0.10.0 django-ses==0.8.4 -django-simple-history==2.0 +django-simple-history==2.1.0 django-splash==0.2.2 django-statici18n==1.4.0 django-storages==1.4.1 @@ -177,7 +177,7 @@ openapi-codec==1.3.2 # via django-rest-swagger path.py==8.2.1 pathtools==0.1.2 paver==1.3.4 -pbr==4.0.3 +pbr==4.0.4 pdfminer==20140328 piexif==1.0.2 pillow==3.4.0 @@ -227,12 +227,12 @@ stevedore==1.10.0 sympy==0.7.1 unicodecsv==0.14.1 uritemplate==3.0.0 # via coreapi -urllib3==1.22 # via elasticsearch +urllib3==1.23 # via elasticsearch user-util==0.1.3 voluptuous==0.11.1 watchdog==0.8.3 web-fragments==0.2.2 -webob==1.8.1 # via xblock +webob==1.8.2 # via xblock wrapt==1.10.5 xblock-review==1.1.5 xblock==1.1.1 diff --git a/requirements/edx/coverage.txt b/requirements/edx/coverage.txt index 2ee11724863..c721171b435 100644 --- a/requirements/edx/coverage.txt +++ b/requirements/edx/coverage.txt @@ -4,6 +4,7 @@ # # make upgrade # + coverage==4.2 diff-cover==0.9.8 inflect==0.3.1 # via jinja2-pluralize diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index ddf237640d4..85a8bf6ce9f 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -4,6 +4,7 @@ # # make upgrade # + -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock -e common/lib/calc -e common/lib/capa @@ -88,7 +89,6 @@ diff-cover==0.9.8 django-appconf==1.0.2 django-babel-underscore==0.5.2 django-babel==0.6.2 -django-birdcage==1.0.0 django-braces==1.13.0 django-classy-tags==0.8.0 django-config-models==0.1.8 @@ -113,7 +113,7 @@ django-require==1.0.11 django-rest-swagger==2.2.0 django-sekizai==0.10.0 django-ses==0.8.4 -django-simple-history==2.0 +django-simple-history==2.1.0 django-splash==0.2.2 django-statici18n==1.4.0 django-storages==1.4.1 @@ -210,7 +210,7 @@ markupsafe==1.0 mccabe==0.6.1 mock==1.0.1 mongoengine==0.10.0 -more-itertools==4.1.0 +more-itertools==4.2.0 moto==0.3.1 mysql-python==1.2.5 needle==0.5.0 @@ -229,7 +229,7 @@ parsel==1.4.0 path.py==8.2.1 pathtools==0.1.2 paver==1.3.4 -pbr==4.0.3 +pbr==4.0.4 pdfminer==20140328 piexif==1.0.2 pillow==3.4.0 @@ -240,7 +240,7 @@ psutil==1.2.1 py2neo==3.1.2 py==1.5.3 pyasn1-modules==0.2.1 -pyasn1==0.4.2 +pyasn1==0.4.3 pycodestyle==2.3.1 pycontracts==1.7.1 pycountry==1.20 @@ -270,7 +270,7 @@ pytest-django==3.1.2 pytest-forked==0.2 pytest-randomly==1.2.3 pytest-xdist==1.22.2 -pytest==3.6.0 +pytest==3.6.1 python-dateutil==2.4.0 python-levenshtein==0.12.0 python-memcached==1.48 @@ -309,8 +309,8 @@ social-auth-app-django==1.2.0 social-auth-core==1.4.0 sorl-thumbnail==12.3 sortedcontainers==0.9.2 -sphinx==1.7.4 -sphinxcontrib-websupport==1.0.1 # via sphinx +sphinx==1.7.5 +sphinxcontrib-websupport==1.1.0 # via sphinx splinter==0.8.0 sqlparse==0.2.4 # via django-debug-toolbar stevedore==1.10.0 @@ -329,7 +329,7 @@ unicodecsv==0.14.1 unidecode==1.0.22 unittest2==1.1.0 uritemplate==3.0.0 -urllib3==1.22 +urllib3==1.23 urlobject==2.4.3 user-util==0.1.3 virtualenv==16.0.0 @@ -337,7 +337,7 @@ voluptuous==0.11.1 w3lib==1.19.0 watchdog==0.8.3 web-fragments==0.2.2 -webob==1.8.1 +webob==1.8.2 werkzeug==0.14.1 wrapt==1.10.5 xblock-review==1.1.5 diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt index f00bbe947b7..697c1669401 100644 --- a/requirements/edx/paver.txt +++ b/requirements/edx/paver.txt @@ -4,6 +4,7 @@ # # make upgrade # + argh==0.26.2 # via watchdog argparse==1.4.0 # via stevedore edx-opaque-keys==0.4.4 @@ -14,7 +15,7 @@ mock==1.0.1 path.py==8.2.1 pathtools==0.1.2 # via watchdog paver==1.3.4 -pbr==4.0.3 # via stevedore +pbr==4.0.4 # via stevedore psutil==1.2.1 pymongo==2.9.1 python-memcached==1.48 diff --git a/requirements/edx/pip-tools.txt b/requirements/edx/pip-tools.txt index e7027f3fb21..44aa65b2a3d 100644 --- a/requirements/edx/pip-tools.txt +++ b/requirements/edx/pip-tools.txt @@ -4,6 +4,7 @@ # # make upgrade # + click==6.7 # via pip-tools first==2.0.1 # via pip-tools pip-tools==2.0.2 diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 219e5cba8f4..5ae1e32a5db 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -4,6 +4,7 @@ # # make upgrade # + -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock -e common/lib/calc -e common/lib/capa @@ -41,7 +42,6 @@ git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@v2.1.6#egg=xblock-d git+https://github.com/open-craft/xblock-poll@7ba819b968fe8faddb78bb22e1fe7637005eb414#egg=xblock-poll==1.2.7 git+https://github.com/edx/xblock-utils.git@v1.1.1#egg=xblock-utils==1.1.1 -e common/lib/xmodule - amqp==1.4.9 analytics-python==1.1.0 anyjson==0.3.3 @@ -86,7 +86,6 @@ diff-cover==0.9.8 django-appconf==1.0.2 django-babel-underscore==0.5.2 django-babel==0.6.2 -django-birdcage==1.0.0 django-braces==1.13.0 django-classy-tags==0.8.0 django-config-models==0.1.8 @@ -110,7 +109,7 @@ django-require==1.0.11 django-rest-swagger==2.2.0 django-sekizai==0.10.0 django-ses==0.8.4 -django-simple-history==2.0 +django-simple-history==2.1.0 django-splash==0.2.2 django-statici18n==1.4.0 django-storages==1.4.1 @@ -203,7 +202,7 @@ markupsafe==1.0 mccabe==0.6.1 # via flake8, pylint mock==1.0.1 mongoengine==0.10.0 -more-itertools==4.1.0 # via pytest +more-itertools==4.2.0 # via pytest moto==0.3.1 mysql-python==1.2.5 needle==0.5.0 # via bok-choy @@ -221,7 +220,7 @@ parsel==1.4.0 # via scrapy path.py==8.2.1 pathtools==0.1.2 paver==1.3.4 -pbr==4.0.3 +pbr==4.0.4 pdfminer==20140328 piexif==1.0.2 pillow==3.4.0 @@ -231,7 +230,7 @@ psutil==1.2.1 py2neo==3.1.2 py==1.5.3 # via pytest, tox pyasn1-modules==0.2.1 # via service-identity -pyasn1==0.4.2 # via pyasn1-modules, service-identity +pyasn1==0.4.3 # via pyasn1-modules, service-identity pycodestyle==2.3.1 pycontracts==1.7.1 pycountry==1.20 @@ -260,7 +259,7 @@ pytest-django==3.1.2 pytest-forked==0.2 # via pytest-xdist pytest-randomly==1.2.3 pytest-xdist==1.22.2 -pytest==3.6.0 +pytest==3.6.1 python-dateutil==2.4.0 python-levenshtein==0.12.0 python-memcached==1.48 @@ -313,7 +312,7 @@ unicodecsv==0.14.1 unidecode==1.0.22 # via python-slugify unittest2==1.1.0 # via testtools uritemplate==3.0.0 -urllib3==1.22 +urllib3==1.23 urlobject==2.4.3 # via pa11ycrawler user-util==0.1.3 virtualenv==16.0.0 # via tox @@ -321,7 +320,7 @@ voluptuous==0.11.1 w3lib==1.19.0 # via parsel, scrapy watchdog==0.8.3 web-fragments==0.2.2 -webob==1.8.1 +webob==1.8.2 werkzeug==0.14.1 # via flask wrapt==1.10.5 xblock-review==1.1.5 -- GitLab