diff --git a/.gitignore b/.gitignore
index dce113d0e7..0a0f43130f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,6 +135,7 @@ lms/lib/comment_client/python
autodeploy.properties
.ws_migrations_complete
dist
+*.bak
# Visual Studio Code
.vscode
diff --git a/lms/djangoapps/course_goals/views.py b/lms/djangoapps/course_goals/views.py
index 89628cca6f..199708e335 100644
--- a/lms/djangoapps/course_goals/views.py
+++ b/lms/djangoapps/course_goals/views.py
@@ -1,6 +1,7 @@
"""
Course Goals Views - includes REST API
"""
+from __future__ import absolute_import
import analytics
from django.contrib.auth import get_user_model
diff --git a/lms/djangoapps/dashboard/sysadmin.py b/lms/djangoapps/dashboard/sysadmin.py
index 5ec0a28c78..bf0d1bd7a1 100644
--- a/lms/djangoapps/dashboard/sysadmin.py
+++ b/lms/djangoapps/dashboard/sysadmin.py
@@ -2,6 +2,7 @@
This module creates a sysadmin dashboard for managing and viewing
courses.
"""
+from __future__ import absolute_import
import unicodecsv as csv
import json
import logging
@@ -127,7 +128,7 @@ class Users(SysadminDashboardView):
continue
try:
testuser = authenticate(username=euser.username, password=epass)
- except (TypeError, PermissionDenied, AttributeError), err:
+ except (TypeError, PermissionDenied, AttributeError) as err:
# Translators: This message means that the user could not be authenticated (that is, we could
# not log them in for some reason - maybe they don't have permission, or their password was wrong)
msg += _('Failed in authenticating {username}, error {error}\n').format(
@@ -235,13 +236,13 @@ class Users(SysadminDashboardView):
if '@' in uname:
try:
user = User.objects.get(email=uname)
- except User.DoesNotExist, err:
+ except User.DoesNotExist as err:
msg = _('Cannot find user with email address {email_addr}').format(email_addr=uname)
return msg
else:
try:
user = User.objects.get(username=uname)
- except User.DoesNotExist, err:
+ except User.DoesNotExist as err:
msg = _('Cannot find user with username {username} - {error}').format(
username=uname,
error=str(err)
@@ -482,7 +483,7 @@ class Courses(SysadminDashboardView):
try:
course = get_course_by_id(course_key)
course_found = True
- except Exception, err: # pylint: disable=broad-except
+ except Exception as err: # pylint: disable=broad-except
self.msg += _(
'Error - cannot get course with ID {0}
{1}'
).format(
diff --git a/lms/djangoapps/edxnotes/views.py b/lms/djangoapps/edxnotes/views.py
index 512beca9d2..1895fa7f58 100644
--- a/lms/djangoapps/edxnotes/views.py
+++ b/lms/djangoapps/edxnotes/views.py
@@ -1,6 +1,7 @@
"""
Views related to EdxNotes.
"""
+from __future__ import absolute_import
import json
import logging
diff --git a/lms/djangoapps/notes/api.py b/lms/djangoapps/notes/api.py
index ebcc5c061c..e59b220fb9 100644
--- a/lms/djangoapps/notes/api.py
+++ b/lms/djangoapps/notes/api.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
import collections
import json
import logging
@@ -10,6 +11,7 @@ from opaque_keys.edx.keys import CourseKey
from courseware.courses import get_course_with_access
from notes.models import Note
from notes.utils import notes_enabled_for_course
+import six
log = logging.getLogger(__name__)
@@ -50,7 +52,7 @@ def api_request(request, course_id, **kwargs):
Raises a 404 if the requested resource does not exist or notes are
disabled for the course.
'''
- assert isinstance(course_id, basestring)
+ assert isinstance(course_id, six.string_types)
course_key = CourseKey.from_string(course_id)
# Verify that the api should be accessible to this course
@@ -68,7 +70,7 @@ def api_request(request, course_id, **kwargs):
log.debug('Resource "{0}" does not exist'.format(resource_name))
raise Http404
- if resource_method not in resource.keys():
+ if resource_method not in list(resource.keys()):
log.debug('Resource "{0}" does not support method "{1}"'.format(resource_name, resource_method))
raise Http404
diff --git a/lms/djangoapps/notifier_api/tests.py b/lms/djangoapps/notifier_api/tests.py
index ac3d9dba8a..3ede34e2c3 100644
--- a/lms/djangoapps/notifier_api/tests.py
+++ b/lms/djangoapps/notifier_api/tests.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
import itertools
import ddt
@@ -18,6 +19,8 @@ from student.tests.factories import CourseEnrollmentFactory, UserFactory
from util.testing import UrlResetMixin
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
+import six
+from six.moves import range
@ddt.ddt
@@ -102,7 +105,7 @@ class NotifierUsersViewSetTest(UrlResetMixin, ModuleStoreTestCase):
itertools.product([True, False], [True, False], [True, False])
):
self._set_up_course(is_course_cohorted, is_user_cohorted, is_moderator)
- expected_course_info[unicode(self.courses[-1].id)] = {
+ expected_course_info[six.text_type(self.courses[-1].id)] = {
"cohort_id": self.cohorts[-1].id if is_user_cohorted else None,
"see_all_cohorts": is_moderator or not is_course_cohorted
}
@@ -114,7 +117,7 @@ class NotifierUsersViewSetTest(UrlResetMixin, ModuleStoreTestCase):
course_id = self.courses[0].id
CourseEnrollment.unenroll(self.user, course_id)
result = self._get_detail()
- self.assertNotIn(unicode(course_id), result["course_info"])
+ self.assertNotIn(six.text_type(course_id), result["course_info"])
def test_course_info_no_enrollments(self):
result = self._get_detail()
@@ -195,11 +198,11 @@ class NotifierUsersViewSetTest(UrlResetMixin, ModuleStoreTestCase):
self.assertEqual(
result_map[self.user.id]["course_info"],
{
- unicode(self.courses[0].id): {
+ six.text_type(self.courses[0].id): {
"cohort_id": self.cohorts[0].id,
"see_all_cohorts": False,
},
- unicode(self.courses[1].id): {
+ six.text_type(self.courses[1].id): {
"cohort_id": None,
"see_all_cohorts": True,
},
@@ -208,7 +211,7 @@ class NotifierUsersViewSetTest(UrlResetMixin, ModuleStoreTestCase):
self.assertEqual(
result_map[other_user.id]["course_info"],
{
- unicode(self.courses[0].id): {
+ six.text_type(self.courses[0].id): {
"cohort_id": None,
"see_all_cohorts": False,
},
diff --git a/openedx/core/djangoapps/api_admin/admin.py b/openedx/core/djangoapps/api_admin/admin.py
index c004449d39..63bdcf4b09 100644
--- a/openedx/core/djangoapps/api_admin/admin.py
+++ b/openedx/core/djangoapps/api_admin/admin.py
@@ -1,4 +1,5 @@
"""Admin views for API managment."""
+from __future__ import absolute_import
from config_models.admin import ConfigurationModelAdmin
from django.contrib import admin
from django.urls import reverse
diff --git a/openedx/core/djangoapps/catalog/views.py b/openedx/core/djangoapps/catalog/views.py
index bbff04869e..740032f052 100644
--- a/openedx/core/djangoapps/catalog/views.py
+++ b/openedx/core/djangoapps/catalog/views.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
from django.conf import settings
from django.core.management import call_command
from django.http import Http404, HttpResponse
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index 056401c72a..e9003cb3d7 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -115,8 +115,8 @@ edx-completion==0.1.7
edx-django-oauth2-provider==1.2.5
edx-django-release-util==0.3.1
edx-django-sites-extensions==2.3.1
-edx-drf-extensions==1.4.0
-edx-enterprise==0.69.4
+edx-drf-extensions==1.5.1
+edx-enterprise==0.69.5
edx-i18n-tools==0.4.5
edx-milestones==0.1.13
edx-oauth2-provider==1.2.2
@@ -209,6 +209,7 @@ redis==2.10.6
reportlab==3.1.44
requests-oauthlib==0.6.1
requests==2.9.1
+rest-condition==1.0.3 # via edx-drf-extensions
rfc6266-parser==0.0.5.post2
rules==1.3
s3transfer==0.1.13 # via boto3
diff --git a/requirements/edx/development.in b/requirements/edx/development.in
index c359c936e1..7d80639ad2 100644
--- a/requirements/edx/development.in
+++ b/requirements/edx/development.in
@@ -18,6 +18,7 @@ pyinotify # More efficient checking for runserver relo
snakefood # Lists dependencies between Python modules, used in scripts/dependencies/*
sphinx # Developer documentation builder
vulture # Detects possible dead/unused code, used in scripts/find-dead-code.sh
+modernize # Used to make Python 2 code more modern with the intention of eventually porting it over to Python 3.
# Performance timer used in modulestore/perf_tests/test_asset_import_export.py
-e git+https://github.com/doctoryes/code_block_timer.git@f3d0629f086bcc649c3c77f4bc5b9c2c8172c3bf#egg=code_block_timer
diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt
index 60d96a7714..85e44ee6f2 100644
--- a/requirements/edx/development.txt
+++ b/requirements/edx/development.txt
@@ -135,8 +135,8 @@ edx-completion==0.1.7
edx-django-oauth2-provider==1.2.5
edx-django-release-util==0.3.1
edx-django-sites-extensions==2.3.1
-edx-drf-extensions==1.4.0
-edx-enterprise==0.69.4
+edx-drf-extensions==1.5.1
+edx-enterprise==0.69.5
edx-i18n-tools==0.4.5
edx-lint==0.5.5
edx-milestones==0.1.13
@@ -209,6 +209,7 @@ markey==0.8
markupsafe==1.0
mccabe==0.6.1
mock==1.0.1
+modernize==0.6.1
mongoengine==0.10.0
more-itertools==4.2.0
moto==0.3.1
@@ -289,13 +290,14 @@ redis==2.10.6
reportlab==3.1.44
requests-oauthlib==0.6.1
requests==2.9.1
+rest-condition==1.0.3
rfc6266-parser==0.0.5.post2
rules==1.3
s3transfer==0.1.13
sailthru-client==2.2.3
scipy==0.14.0
scrapy==1.1.2
-selenium==3.12.0
+selenium==3.13.0
semantic-version==2.6.0
service-identity==17.0.0
shapely==1.2.16
diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt
index 74c060e015..7634010dd7 100644
--- a/requirements/edx/testing.txt
+++ b/requirements/edx/testing.txt
@@ -130,8 +130,8 @@ edx-completion==0.1.7
edx-django-oauth2-provider==1.2.5
edx-django-release-util==0.3.1
edx-django-sites-extensions==2.3.1
-edx-drf-extensions==1.4.0
-edx-enterprise==0.69.4
+edx-drf-extensions==1.5.1
+edx-enterprise==0.69.5
edx-i18n-tools==0.4.5
edx-lint==0.5.5
edx-milestones==0.1.13
@@ -278,13 +278,14 @@ redis==2.10.6
reportlab==3.1.44
requests-oauthlib==0.6.1
requests==2.9.1
+rest-condition==1.0.3
rfc6266-parser==0.0.5.post2
rules==1.3
s3transfer==0.1.13
sailthru-client==2.2.3
scipy==0.14.0
scrapy==1.1.2 # via pa11ycrawler
-selenium==3.12.0
+selenium==3.13.0
semantic-version==2.6.0
service-identity==17.0.0 # via scrapy
shapely==1.2.16