diff --git a/lms/djangoapps/mailing/management/commands/mailchimp_id.py b/lms/djangoapps/mailing/management/commands/mailchimp_id.py
index ca30454dd7..f8b195b400 100644
--- a/lms/djangoapps/mailing/management/commands/mailchimp_id.py
+++ b/lms/djangoapps/mailing/management/commands/mailchimp_id.py
@@ -42,8 +42,8 @@ class Command(BaseCommand):
list_with_id = by_web_id.get(web_id, None)
if list_with_id:
- print(u"id: {} for web_id: {}".format(list_with_id['id'], web_id))
- print(u"list name: {}".format(list_with_id['name']))
+ print("id: {} for web_id: {}".format(list_with_id['id'], web_id))
+ print("list name: {}".format(list_with_id['name']))
else:
- print(u"list with web_id: {} not found.".format(web_id))
+ print(f"list with web_id: {web_id} not found.")
sys.exit(1)
diff --git a/lms/djangoapps/mailing/management/commands/mailchimp_sync_course.py b/lms/djangoapps/mailing/management/commands/mailchimp_sync_course.py
index 3157ad62c9..2a33945d06 100644
--- a/lms/djangoapps/mailing/management/commands/mailchimp_sync_course.py
+++ b/lms/djangoapps/mailing/management/commands/mailchimp_sync_course.py
@@ -10,8 +10,6 @@ import random
from collections import namedtuple
from itertools import chain
-import six
-from six.moves import range
from django.core.management.base import BaseCommand
from mailsnake import MailSnake
from opaque_keys.edx.keys import CourseKey
@@ -59,7 +57,7 @@ class Command(BaseCommand):
course_id = options['course_id']
num_segments = options['num_segments']
- log.info(u'Syncronizing email list for %s', course_id)
+ log.info('Syncronizing email list for %s', course_id)
mailchimp = connect_mailchimp(key)
@@ -83,7 +81,7 @@ class Command(BaseCommand):
unsubscribe(mailchimp, list_id, non_enrolled_emails)
- subscribed = subscribed.union(set(d['EMAIL'] for d in to_subscribe))
+ subscribed = subscribed.union({d['EMAIL'] for d in to_subscribe})
make_segments(mailchimp, list_id, num_segments, subscribed)
@@ -111,7 +109,7 @@ def verify_list(mailchimp, list_id, course_id):
list_name = lists[0]['name']
- log.debug(u'list name: %s', list_name)
+ log.debug('list name: %s', list_name)
# check that we are connecting to the correct list
parts = course_id.replace('_', ' ').replace('/', ' ').split()
@@ -246,7 +244,7 @@ def update_merge_tags(mailchimp, list_id, tag_names):
The purpose of this function is unclear.
"""
mc_vars = mailchimp.listMergeVars(id=list_id)
- mc_names = set(v['name'] for v in mc_vars)
+ mc_names = {v['name'] for v in mc_vars}
mc_merge = mailchimp.listMergeVarAdd
@@ -288,7 +286,7 @@ def subscribe_with_data(mailchimp, list_id, user_data):
Returns None
"""
- format_entry = lambda e: {name_to_tag(k): v for k, v in six.iteritems(e)}
+ format_entry = lambda e: {name_to_tag(k): v for k, v in e.items()}
formated_data = list(format_entry(e) for e in user_data)
# send the updates in batches of a fixed size
@@ -299,7 +297,7 @@ def subscribe_with_data(mailchimp, list_id, user_data):
update_existing=True)
log.debug(
- u"Added: %s Error on: %s", result['add_count'], result['error_count']
+ "Added: %s Error on: %s", result['add_count'], result['error_count']
)
@@ -334,7 +332,7 @@ def make_segments(mailchimp, list_id, count, emails):
# create segments and add emails
for seg in range(count):
- name = 'random_{0:002}'.format(seg)
+ name = f'random_{seg:002}'
seg_id = mailchimp.listStaticSegmentAdd(id=list_id, name=name)
for batch in chunk(chunks[seg], BATCH_SIZE):
mailchimp.listStaticSegmentMembersAdd(
diff --git a/lms/djangoapps/mobile_api/admin.py b/lms/djangoapps/mobile_api/admin.py
index 841fb4b0c7..fde951f309 100644
--- a/lms/djangoapps/mobile_api/admin.py
+++ b/lms/djangoapps/mobile_api/admin.py
@@ -17,7 +17,7 @@ class AppVersionConfigAdmin(admin.ModelAdmin):
fields = ('platform', 'version', 'expire_at', 'enabled')
list_filter = ['platform']
- class Meta(object):
+ class Meta:
ordering = ['-major_version', '-minor_version', '-patch_version']
def get_list_display(self, __):
diff --git a/lms/djangoapps/mobile_api/course_info/tests.py b/lms/djangoapps/mobile_api/course_info/tests.py
index 4f5556fa89..40a0a3ed28 100644
--- a/lms/djangoapps/mobile_api/course_info/tests.py
+++ b/lms/djangoapps/mobile_api/course_info/tests.py
@@ -6,7 +6,6 @@ Tests for course_info
import ddt
from django.conf import settings
from milestones.tests.utils import MilestonesTestCaseMixin
-from six.moves import range
from lms.djangoapps.mobile_api.testutils import MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTestMixin
from lms.djangoapps.mobile_api.utils import API_V1, API_V05
@@ -24,7 +23,7 @@ class TestUpdates(MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTest
REVERSE_INFO = {'name': 'course-updates-list', 'params': ['course_id', 'api_version']}
def verify_success(self, response):
- super(TestUpdates, self).verify_success(response) # lint-amnesty, pylint: disable=super-with-arguments
+ super().verify_success(response)
assert response.data == []
@ddt.data(
@@ -67,7 +66,7 @@ class TestUpdates(MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTest
# old format stores the updates with the newest first
for num in range(num_updates, 0, -1):
update_data += "
Date" + str(num) + "
Update" + str(num) + ""
- course_updates.data = u"" + update_data + "
"
+ course_updates.data = "" + update_data + "
"
modulestore().update_item(course_updates, self.user.id)
# call API
diff --git a/lms/djangoapps/mobile_api/course_info/urls.py b/lms/djangoapps/mobile_api/course_info/urls.py
index 55c3a3ded3..eebf3fff50 100644
--- a/lms/djangoapps/mobile_api/course_info/urls.py
+++ b/lms/djangoapps/mobile_api/course_info/urls.py
@@ -10,12 +10,12 @@ from .views import CourseHandoutsList, CourseUpdatesList
urlpatterns = [
url(
- r'^{}/handouts$'.format(settings.COURSE_ID_PATTERN),
+ fr'^{settings.COURSE_ID_PATTERN}/handouts$',
CourseHandoutsList.as_view(),
name='course-handouts-list'
),
url(
- r'^{}/updates$'.format(settings.COURSE_ID_PATTERN),
+ fr'^{settings.COURSE_ID_PATTERN}/updates$',
CourseUpdatesList.as_view(),
name='course-updates-list'
),
diff --git a/lms/djangoapps/mobile_api/course_info/views.py b/lms/djangoapps/mobile_api/course_info/views.py
index 175889515c..6d78f05918 100644
--- a/lms/djangoapps/mobile_api/course_info/views.py
+++ b/lms/djangoapps/mobile_api/course_info/views.py
@@ -6,9 +6,9 @@ Views for course info API
from rest_framework import generics
from rest_framework.response import Response
+from common.djangoapps.static_replace import make_static_urls_absolute
from lms.djangoapps.courseware.courses import get_course_info_section_module
from openedx.core.lib.xblock_utils import get_course_update_items
-from common.djangoapps.static_replace import make_static_urls_absolute
from ..decorators import mobile_course_access, mobile_view
diff --git a/lms/djangoapps/mobile_api/middleware.py b/lms/djangoapps/mobile_api/middleware.py
index 88c593d5ec..41af2b688b 100644
--- a/lms/djangoapps/mobile_api/middleware.py
+++ b/lms/djangoapps/mobile_api/middleware.py
@@ -10,7 +10,6 @@ from django.core.cache import cache
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
from pytz import UTC
-import six
from lms.djangoapps.mobile_api.mobile_platform import MobilePlatform
from lms.djangoapps.mobile_api.models import AppVersionConfig
@@ -79,7 +78,7 @@ class AppVersionUpgrade(MiddlewareMixin):
Returns:
string: Cache key to be used.
"""
- return "mobile_api.app_version_upgrade.{}.{}".format(field, key)
+ return f"mobile_api.app_version_upgrade.{field}.{key}"
def _get_version_info(self, request):
"""
@@ -112,7 +111,7 @@ class AppVersionUpgrade(MiddlewareMixin):
request_cache_dict[self.LAST_SUPPORTED_DATE_HEADER] = last_supported_date
latest_version = cached_data.get(latest_version_cache_key)
- if not (latest_version and isinstance(latest_version, six.text_type)):
+ if not (latest_version and isinstance(latest_version, str)):
latest_version = self._get_latest_version(platform.NAME)
cache.set(latest_version_cache_key, latest_version, self.CACHE_TIMEOUT)
request_cache_dict[self.LATEST_VERSION_HEADER] = latest_version
diff --git a/lms/djangoapps/mobile_api/migrations/0001_initial.py b/lms/djangoapps/mobile_api/migrations/0001_initial.py
index ae604e95bc..4b3bbfa016 100644
--- a/lms/djangoapps/mobile_api/migrations/0001_initial.py
+++ b/lms/djangoapps/mobile_api/migrations/0001_initial.py
@@ -1,6 +1,3 @@
-# -*- coding: utf-8 -*-
-
-
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
@@ -19,7 +16,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
- ('video_profiles', models.TextField(help_text=u'A comma-separated list of names of profiles to include for videos returned from the mobile API.', blank=True)),
+ ('video_profiles', models.TextField(help_text='A comma-separated list of names of profiles to include for videos returned from the mobile API.', blank=True)),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
],
options={
diff --git a/lms/djangoapps/mobile_api/migrations/0002_auto_20160406_0904.py b/lms/djangoapps/mobile_api/migrations/0002_auto_20160406_0904.py
index 602317c69d..8c4db5bbb7 100644
--- a/lms/djangoapps/mobile_api/migrations/0002_auto_20160406_0904.py
+++ b/lms/djangoapps/mobile_api/migrations/0002_auto_20160406_0904.py
@@ -1,6 +1,3 @@
-# -*- coding: utf-8 -*-
-
-
from django.db import migrations, models
@@ -15,12 +12,12 @@ class Migration(migrations.Migration):
name='AppVersionConfig',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('platform', models.CharField(max_length=50, choices=[(u'Android', u'Android'), (u'iOS', u'iOS')])),
- ('version', models.CharField(help_text=u'Version should be in the format X.X.X.Y where X is a number and Y is alphanumeric', max_length=50)),
+ ('platform', models.CharField(max_length=50, choices=[('Android', 'Android'), ('iOS', 'iOS')])),
+ ('version', models.CharField(help_text='Version should be in the format X.X.X.Y where X is a number and Y is alphanumeric', max_length=50)),
('major_version', models.IntegerField()),
('minor_version', models.IntegerField()),
('patch_version', models.IntegerField()),
- ('expire_at', models.DateTimeField(null=True, verbose_name=u'Expiry date for platform version', blank=True)),
+ ('expire_at', models.DateTimeField(null=True, verbose_name='Expiry date for platform version', blank=True)),
('enabled', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
@@ -31,6 +28,6 @@ class Migration(migrations.Migration):
),
migrations.AlterUniqueTogether(
name='appversionconfig',
- unique_together=set([('platform', 'version')]),
+ unique_together={('platform', 'version')},
),
]
diff --git a/lms/djangoapps/mobile_api/migrations/0003_ignore_mobile_available_flag.py b/lms/djangoapps/mobile_api/migrations/0003_ignore_mobile_available_flag.py
index 89816f0bd5..565281a6c6 100644
--- a/lms/djangoapps/mobile_api/migrations/0003_ignore_mobile_available_flag.py
+++ b/lms/djangoapps/mobile_api/migrations/0003_ignore_mobile_available_flag.py
@@ -1,6 +1,3 @@
-# -*- coding: utf-8 -*-
-
-
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
diff --git a/lms/djangoapps/mobile_api/mobile_platform.py b/lms/djangoapps/mobile_api/mobile_platform.py
index 61ec5edd1e..fee0919e5b 100644
--- a/lms/djangoapps/mobile_api/mobile_platform.py
+++ b/lms/djangoapps/mobile_api/mobile_platform.py
@@ -6,10 +6,8 @@ Platform related Operations for Mobile APP
import abc
import re
-import six
-
-class MobilePlatform(six.with_metaclass(abc.ABCMeta)):
+class MobilePlatform(metaclass=abc.ABCMeta):
"""
MobilePlatform class creates an instance of platform based on user agent and supports platform
related operations.
@@ -58,14 +56,14 @@ class IOS(MobilePlatform):
""" iOS platform """
USER_AGENT_REGEX = (r'\((?P[0-9]+.[0-9]+.[0-9]+(\.[0-9a-zA-Z]*)?); OS Version [0-9.]+ '
r'\(Build [0-9a-zA-Z]*\)\)')
- NAME = u"iOS"
+ NAME = "iOS"
class Android(MobilePlatform):
""" Android platform """
USER_AGENT_REGEX = (r'Dalvik/[.0-9]+ \(Linux; U; Android [.0-9]+; (.*) (Build|MIUI)/[0-9a-zA-Z-.]*\) '
r'(.*)/(?P[0-9]+.[0-9]+.[0-9]+(\.[0-9a-zA-Z]*)?)')
- NAME = u"Android"
+ NAME = "Android"
# a list of all supported mobile platforms
diff --git a/lms/djangoapps/mobile_api/models.py b/lms/djangoapps/mobile_api/models.py
index 4e423cc0db..61c6a815d2 100644
--- a/lms/djangoapps/mobile_api/models.py
+++ b/lms/djangoapps/mobile_api/models.py
@@ -22,10 +22,10 @@ class MobileApiConfig(ConfigurationModel):
"""
video_profiles = models.TextField(
blank=True,
- help_text=u"A comma-separated list of names of profiles to include for videos returned from the mobile API."
+ help_text="A comma-separated list of names of profiles to include for videos returned from the mobile API."
)
- class Meta(object):
+ class Meta:
app_label = "mobile_api"
@classmethod
@@ -51,12 +51,12 @@ class AppVersionConfig(models.Model):
version = models.CharField(
max_length=50,
blank=False,
- help_text=u"Version should be in the format X.X.X.Y where X is a number and Y is alphanumeric"
+ help_text="Version should be in the format X.X.X.Y where X is a number and Y is alphanumeric"
)
major_version = models.IntegerField()
minor_version = models.IntegerField()
patch_version = models.IntegerField()
- expire_at = models.DateTimeField(null=True, blank=True, verbose_name=u"Expiry date for platform version")
+ expire_at = models.DateTimeField(null=True, blank=True, verbose_name="Expiry date for platform version")
enabled = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -67,7 +67,7 @@ class AppVersionConfig(models.Model):
ordering = ['-major_version', '-minor_version', '-patch_version']
def __str__(self):
- return "{}_{}".format(self.platform, self.version)
+ return f"{self.platform}_{self.version}"
@classmethod
def latest_version(cls, platform):
@@ -88,7 +88,7 @@ class AppVersionConfig(models.Model):
def save(self, *args, **kwargs): # lint-amnesty, pylint: disable=signature-differs
""" parses version into major, minor and patch versions before saving """
self.major_version, self.minor_version, self.patch_version = utils.parsed_version(self.version)
- super(AppVersionConfig, self).save(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
+ super().save(*args, **kwargs)
class IgnoreMobileAvailableFlagConfig(ConfigurationModel):
@@ -102,5 +102,5 @@ class IgnoreMobileAvailableFlagConfig(ConfigurationModel):
.. no_pii:
"""
- class Meta(object):
+ class Meta:
app_label = "mobile_api"
diff --git a/lms/djangoapps/mobile_api/tests/test_decorator.py b/lms/djangoapps/mobile_api/tests/test_decorator.py
index 5134268def..4e18d9703d 100644
--- a/lms/djangoapps/mobile_api/tests/test_decorator.py
+++ b/lms/djangoapps/mobile_api/tests/test_decorator.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Tests for mobile API utilities.
"""
diff --git a/lms/djangoapps/mobile_api/tests/test_middleware.py b/lms/djangoapps/mobile_api/tests/test_middleware.py
index 8cf3fbc855..3db1be023d 100644
--- a/lms/djangoapps/mobile_api/tests/test_middleware.py
+++ b/lms/djangoapps/mobile_api/tests/test_middleware.py
@@ -4,9 +4,9 @@ Tests for Version Based App Upgrade Middleware
from datetime import datetime
+from unittest import mock
import ddt
-import mock
from django.core.cache import caches
from django.http import HttpRequest, HttpResponse
from pytz import UTC
@@ -25,7 +25,7 @@ class TestAppVersionUpgradeMiddleware(CacheIsolationTestCase):
ENABLED_CACHES = ['default']
def setUp(self):
- super(TestAppVersionUpgradeMiddleware, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
+ super().setUp()
self.middleware = AppVersionUpgrade()
self.set_app_version_config()
diff --git a/lms/djangoapps/mobile_api/tests/test_milestones.py b/lms/djangoapps/mobile_api/tests/test_milestones.py
index ef97ef3f86..d9c233530b 100644
--- a/lms/djangoapps/mobile_api/tests/test_milestones.py
+++ b/lms/djangoapps/mobile_api/tests/test_milestones.py
@@ -3,19 +3,19 @@ Milestone related tests for the mobile_api
"""
-import six
+from unittest.mock import patch
+
from crum import set_current_request
from django.conf import settings
-from mock import patch
+from common.djangoapps.util.milestones_helpers import add_prerequisite_course, fulfill_course_milestone
from lms.djangoapps.courseware.access_response import MilestoneAccessError
from lms.djangoapps.courseware.tests.test_entrance_exam import add_entrance_exam_milestone, answer_entrance_exam_problem
from openedx.core.djangolib.testing.utils import get_mock_request
-from common.djangoapps.util.milestones_helpers import add_prerequisite_course, fulfill_course_milestone
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
-class MobileAPIMilestonesMixin(object):
+class MobileAPIMilestonesMixin:
"""
Tests the Mobile API decorators for milestones.
@@ -114,7 +114,7 @@ class MobileAPIMilestonesMixin(object):
add_entrance_exam_milestone(self.course, self.entrance_exam)
self.course.entrance_exam_minimum_score_pct = 0.50
- self.course.entrance_exam_id = six.text_type(self.entrance_exam.location)
+ self.course.entrance_exam_id = str(self.entrance_exam.location)
self.store.update_item(self.course, self.user.id)
def _add_prerequisite_course(self):
diff --git a/lms/djangoapps/mobile_api/tests/test_model.py b/lms/djangoapps/mobile_api/tests/test_model.py
index a1e172215e..c63d0f271e 100644
--- a/lms/djangoapps/mobile_api/tests/test_model.py
+++ b/lms/djangoapps/mobile_api/tests/test_model.py
@@ -96,13 +96,13 @@ class TestMobileApiConfig(TestCase):
"""Check that video_profiles config is returned in order as a list"""
MobileApiConfig(video_profiles="mobile_low,mobile_high,youtube").save()
video_profile_list = MobileApiConfig.get_video_profiles()
- assert video_profile_list == [u'mobile_low', u'mobile_high', u'youtube']
+ assert video_profile_list == ['mobile_low', 'mobile_high', 'youtube']
def test_video_profile_list_with_whitespace(self):
"""Check video_profiles config with leading and trailing whitespace"""
MobileApiConfig(video_profiles=" mobile_low , mobile_high,youtube ").save()
video_profile_list = MobileApiConfig.get_video_profiles()
- assert video_profile_list == [u'mobile_low', u'mobile_high', u'youtube']
+ assert video_profile_list == ['mobile_low', 'mobile_high', 'youtube']
def test_empty_video_profile(self):
"""Test an empty video_profile"""
diff --git a/lms/djangoapps/mobile_api/testutils.py b/lms/djangoapps/mobile_api/testutils.py
index 384076fbd3..8eeabd9413 100644
--- a/lms/djangoapps/mobile_api/testutils.py
+++ b/lms/djangoapps/mobile_api/testutils.py
@@ -13,24 +13,23 @@ Test utilities for mobile API tests:
import datetime
+from unittest.mock import patch
import ddt
import pytz
-import six
from django.conf import settings
from django.urls import reverse
from django.utils import timezone
-from mock import patch
from opaque_keys.edx.keys import CourseKey
from rest_framework.test import APITestCase
+from common.djangoapps.student import auth
+from common.djangoapps.student.models import CourseEnrollment
from lms.djangoapps.courseware.access_response import MobileAvailabilityError, StartDateError, VisibilityError
from lms.djangoapps.courseware.tests.factories import UserFactory
from lms.djangoapps.mobile_api.models import IgnoreMobileAvailableFlagConfig
from lms.djangoapps.mobile_api.tests.test_milestones import MobileAPIMilestonesMixin
from lms.djangoapps.mobile_api.utils import API_V1
-from common.djangoapps.student import auth
-from common.djangoapps.student.models import CourseEnrollment
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@@ -43,7 +42,7 @@ class MobileAPITestCase(ModuleStoreTestCase, APITestCase):
They may also override any of the methods defined in this class to control the behavior of the TestMixins.
"""
def setUp(self):
- super(MobileAPITestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
+ super().setUp()
self.course = CourseFactory.create(
mobile_available=True,
static_asset_path="needed_for_split",
@@ -57,7 +56,7 @@ class MobileAPITestCase(ModuleStoreTestCase, APITestCase):
IgnoreMobileAvailableFlagConfig(enabled=False).save()
def tearDown(self):
- super(MobileAPITestCase, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
+ super().tearDown()
self.logout()
def login(self):
@@ -96,7 +95,7 @@ class MobileAPITestCase(ModuleStoreTestCase, APITestCase):
"""Base implementation that returns URL for endpoint that's being tested."""
reverse_args = reverse_args or {}
if 'course_id' in self.REVERSE_INFO['params']:
- reverse_args.update({'course_id': six.text_type(kwargs.get('course_id', self.course.id))})
+ reverse_args.update({'course_id': str(kwargs.get('course_id', self.course.id))})
if 'username' in self.REVERSE_INFO['params']:
reverse_args.update({'username': kwargs.get('username', self.user.username)})
if 'api_version' in self.REVERSE_INFO['params']:
@@ -108,7 +107,7 @@ class MobileAPITestCase(ModuleStoreTestCase, APITestCase):
return self.client.get(url, data=data)
-class MobileAuthTestMixin(object):
+class MobileAuthTestMixin:
"""
Test Mixin for testing APIs decorated with mobile_view.
"""
diff --git a/lms/djangoapps/mobile_api/users/serializers.py b/lms/djangoapps/mobile_api/users/serializers.py
index b774379975..a4418696fd 100644
--- a/lms/djangoapps/mobile_api/users/serializers.py
+++ b/lms/djangoapps/mobile_api/users/serializers.py
@@ -3,15 +3,14 @@ Serializer for user API
"""
-import six
from rest_framework import serializers
from rest_framework.reverse import reverse
-from lms.djangoapps.courseware.access import has_access
-from lms.djangoapps.certificates.api import certificate_downloadable_status
-from openedx.features.course_duration_limits.access import get_user_course_expiration_date
from common.djangoapps.student.models import CourseEnrollment, User
from common.djangoapps.util.course import get_encoded_course_sharing_utm_params, get_link_for_about_page
+from lms.djangoapps.certificates.api import certificate_downloadable_status
+from lms.djangoapps.courseware.access import has_access
+from openedx.features.course_duration_limits.access import get_user_course_expiration_date
class CourseOverviewField(serializers.RelatedField): # lint-amnesty, pylint: disable=abstract-method
@@ -19,7 +18,7 @@ class CourseOverviewField(serializers.RelatedField): # lint-amnesty, pylint: di
Custom field to wrap a CourseOverview object. Read-only.
"""
def to_representation(self, course_overview): # lint-amnesty, pylint: disable=arguments-differ
- course_id = six.text_type(course_overview.id)
+ course_id = str(course_overview.id)
request = self.context.get('request')
api_version = self.context.get('api_version')
enrollment = CourseEnrollment.get_enrollment(user=self.context.get('request').user, course_key=course_id)
@@ -111,7 +110,7 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer):
else:
return {}
- class Meta(object):
+ class Meta:
model = CourseEnrollment
fields = ('audit_access_expires', 'created', 'mode', 'is_active', 'course', 'certificate')
lookup_field = 'username'
@@ -122,7 +121,7 @@ class CourseEnrollmentSerializerv05(CourseEnrollmentSerializer):
Serializes CourseEnrollment models for v0.5 api
Does not include 'audit_access_expires' field that is present in v1 api
"""
- class Meta(object):
+ class Meta:
model = CourseEnrollment
fields = ('created', 'mode', 'is_active', 'course', 'certificate')
lookup_field = 'username'
@@ -145,7 +144,7 @@ class UserSerializer(serializers.ModelSerializer):
request=request
)
- class Meta(object):
+ class Meta:
model = User
fields = ('id', 'username', 'email', 'name', 'course_enrollments')
lookup_field = 'username'
diff --git a/lms/djangoapps/mobile_api/users/tests.py b/lms/djangoapps/mobile_api/users/tests.py
index 68df5a04e9..dc73b85850 100644
--- a/lms/djangoapps/mobile_api/users/tests.py
+++ b/lms/djangoapps/mobile_api/users/tests.py
@@ -4,10 +4,11 @@ Tests for users API
import datetime
+from unittest.mock import patch
+from urllib.parse import parse_qs
import ddt
import pytz
-import six
from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing
from django.conf import settings
from django.template import defaultfilters
@@ -15,15 +16,16 @@ from django.test import RequestFactory, override_settings
from django.utils import timezone
from django.utils.timezone import now
from milestones.tests.utils import MilestonesTestCaseMixin
-from mock import patch
-from six.moves import range
-from six.moves.urllib.parse import parse_qs
from common.djangoapps.course_modes.models import CourseMode
-from lms.djangoapps.courseware.access_response import MilestoneAccessError, StartDateError, VisibilityError
+from common.djangoapps.student.models import CourseEnrollment
+from common.djangoapps.student.tests.factories import CourseEnrollmentFactory
+from common.djangoapps.util.milestones_helpers import set_prerequisite_courses
+from common.djangoapps.util.testing import UrlResetMixin
from lms.djangoapps.certificates.api import generate_user_certificates
from lms.djangoapps.certificates.models import CertificateStatuses
from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory
+from lms.djangoapps.courseware.access_response import MilestoneAccessError, StartDateError, VisibilityError
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from lms.djangoapps.mobile_api.testutils import (
MobileAPITestCase,
@@ -36,10 +38,6 @@ from openedx.core.djangoapps.schedules.tests.factories import ScheduleFactory
from openedx.core.lib.courses import course_image_url
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
from openedx.features.course_experience.tests.views.helpers import add_course_mode
-from common.djangoapps.student.models import CourseEnrollment
-from common.djangoapps.student.tests.factories import CourseEnrollmentFactory
-from common.djangoapps.util.milestones_helpers import set_prerequisite_courses
-from common.djangoapps.util.testing import UrlResetMixin
from xmodule.course_module import DEFAULT_START_DATE
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
@@ -118,13 +116,13 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
@patch.dict(settings.FEATURES, {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
- super(TestUserEnrollmentApi, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
+ super().setUp()
def verify_success(self, response):
"""
Verifies user course enrollment response for success
"""
- super(TestUserEnrollmentApi, self).verify_success(response) # lint-amnesty, pylint: disable=super-with-arguments
+ super().verify_success(response)
courses = response.data
assert len(courses) == 1
@@ -132,7 +130,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
assert 'courses/{}/about'.format(self.course.id) in found_course['course_about']
assert 'course_info/{}/updates'.format(self.course.id) in found_course['course_updates']
assert 'course_info/{}/handouts'.format(self.course.id) in found_course['course_handouts']
- assert found_course['id'] == six.text_type(self.course.id)
+ assert found_course['id'] == str(self.course.id)
assert courses[0]['mode'] == CourseMode.DEFAULT_MODE_SLUG
assert courses[0]['course']['subscription_id'] == self.course.clean_id(padding_char='_')
@@ -161,7 +159,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
response = self.api_response(api_version=api_version)
for course_index in range(num_courses):
assert response.data[course_index]['course']['id'] ==\
- six.text_type(courses[((num_courses - course_index) - 1)].id)
+ str(courses[((num_courses - course_index) - 1)].id)
@ddt.data(API_V05, API_V1)
@patch.dict(settings.FEATURES, {
@@ -174,7 +172,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
course_with_prereq = CourseFactory.create(start=self.LAST_WEEK, mobile_available=True)
prerequisite_course = CourseFactory.create()
- set_prerequisite_courses(course_with_prereq.id, [six.text_type(prerequisite_course.id)])
+ set_prerequisite_courses(course_with_prereq.id, [str(prerequisite_course.id)])
# Create list of courses with various expected courseware_access responses and corresponding expected codes
courses = [
@@ -423,7 +421,7 @@ class CourseStatusAPITestCase(MobileAPITestCase):
"""
Creates a basic course structure for our course
"""
- super(CourseStatusAPITestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
+ super().setUp()
self.section = ItemFactory.create(
parent=self.course,
@@ -456,8 +454,8 @@ class TestCourseStatusGET(CourseStatusAPITestCase, MobileAuthUserTestMixin,
self.login_and_enroll()
response = self.api_response(api_version=API_V05)
- assert response.data['last_visited_module_id'] == six.text_type(self.sub_section.location)
- assert response.data['last_visited_module_path'] == [six.text_type(module.location) for module in
+ assert response.data['last_visited_module_id'] == str(self.sub_section.location)
+ assert response.data['last_visited_module_path'] == [str(module.location) for module in
[self.sub_section, self.section, self.course]]
def test_success_v1(self):
@@ -465,7 +463,7 @@ class TestCourseStatusGET(CourseStatusAPITestCase, MobileAuthUserTestMixin,
self.login_and_enroll()
submit_completions_for_testing(self.user, [self.unit.location])
response = self.api_response(api_version=API_V1)
- assert response.data['last_visited_block_id'] == six.text_type(self.unit.location)
+ assert response.data['last_visited_block_id'] == str(self.unit.location)
class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,
@@ -479,8 +477,8 @@ class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,
def test_success(self):
self.login_and_enroll()
- response = self.api_response(data={"last_visited_module_id": six.text_type(self.other_unit.location)})
- assert response.data['last_visited_module_id'] == six.text_type(self.other_sub_section.location)
+ response = self.api_response(data={"last_visited_module_id": str(self.other_unit.location)})
+ assert response.data['last_visited_module_id'] == str(self.other_sub_section.location)
def test_invalid_module(self):
self.login_and_enroll()
@@ -498,7 +496,7 @@ class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,
past_date = datetime.datetime.now()
response = self.api_response(
data={
- "last_visited_module_id": six.text_type(self.other_unit.location),
+ "last_visited_module_id": str(self.other_unit.location),
"modification_date": past_date.isoformat()
},
expected_response_code=400
@@ -513,16 +511,16 @@ class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,
self.login_and_enroll()
# save something so we have an initial date
- self.api_response(data={"last_visited_module_id": six.text_type(initial_unit.location)})
+ self.api_response(data={"last_visited_module_id": str(initial_unit.location)})
# now actually update it
response = self.api_response(
data={
- "last_visited_module_id": six.text_type(update_unit.location),
+ "last_visited_module_id": str(update_unit.location),
"modification_date": date.isoformat()
}
)
- assert response.data['last_visited_module_id'] == six.text_type(expected_subsection.location)
+ assert response.data['last_visited_module_id'] == str(expected_subsection.location)
def test_old_date(self):
self.login_and_enroll()
@@ -538,11 +536,11 @@ class TestCourseStatusPATCH(CourseStatusAPITestCase, MobileAuthUserTestMixin,
self.login_and_enroll()
response = self.api_response(
data={
- "last_visited_module_id": six.text_type(self.other_unit.location),
+ "last_visited_module_id": str(self.other_unit.location),
"modification_date": timezone.now().isoformat()
}
)
- assert response.data['last_visited_module_id'] == six.text_type(self.other_sub_section.location)
+ assert response.data['last_visited_module_id'] == str(self.other_sub_section.location)
def test_invalid_date(self):
self.login_and_enroll()
@@ -560,7 +558,7 @@ class TestCourseEnrollmentSerializer(MobileAPITestCase, MilestonesTestCaseMixin)
ENABLED_SIGNALS = ['course_published']
def setUp(self):
- super(TestCourseEnrollmentSerializer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
+ super().setUp()
self.login_and_enroll()
self.request = RequestFactory().get('/')
self.request.user = self.user
diff --git a/lms/djangoapps/mobile_api/users/urls.py b/lms/djangoapps/mobile_api/users/urls.py
index 4a580693d1..419d9d67f0 100644
--- a/lms/djangoapps/mobile_api/users/urls.py
+++ b/lms/djangoapps/mobile_api/users/urls.py
@@ -15,7 +15,7 @@ urlpatterns = [
UserCourseEnrollmentsList.as_view(),
name='courseenrollment-detail'
),
- url('^{}/course_status_info/{}'.format(settings.USERNAME_PATTERN, settings.COURSE_ID_PATTERN),
+ url(f'^{settings.USERNAME_PATTERN}/course_status_info/{settings.COURSE_ID_PATTERN}',
UserCourseStatus.as_view(),
name='user-course-status')
]
diff --git a/lms/djangoapps/mobile_api/users/views.py b/lms/djangoapps/mobile_api/users/views.py
index 7fec2ebc19..3647110d59 100644
--- a/lms/djangoapps/mobile_api/users/views.py
+++ b/lms/djangoapps/mobile_api/users/views.py
@@ -3,9 +3,9 @@ Views for user API
"""
-import six
-from completion.utilities import get_key_to_last_completed_block
from completion.exceptions import UnavailableCompletionData
+from completion.utilities import get_key_to_last_completed_block
+from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.contrib.auth.signals import user_logged_in
from django.shortcuts import redirect
from django.utils import dateparse
@@ -16,17 +16,16 @@ from rest_framework.decorators import api_view
from rest_framework.response import Response
from xblock.fields import Scope
from xblock.runtime import KeyValueStore
-from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
+from common.djangoapps.student.models import CourseEnrollment, User # lint-amnesty, pylint: disable=reimported
from lms.djangoapps.courseware.access import is_mobile_available_for_user
+from lms.djangoapps.courseware.access_utils import ACCESS_GRANTED
from lms.djangoapps.courseware.courses import get_current_child
from lms.djangoapps.courseware.model_data import FieldDataCache
from lms.djangoapps.courseware.module_render import get_module_for_descriptor
from lms.djangoapps.courseware.views.index import save_positions_recursively_up
-from lms.djangoapps.courseware.access_utils import ACCESS_GRANTED
-from lms.djangoapps.mobile_api.utils import API_V05, API_V1
+from lms.djangoapps.mobile_api.utils import API_V1, API_V05
from openedx.features.course_duration_limits.access import check_course_expired
-from common.djangoapps.student.models import CourseEnrollment, User # lint-amnesty, pylint: disable=reimported
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -72,7 +71,7 @@ class UserDetail(generics.RetrieveAPIView):
lookup_field = 'username'
def get_serializer_context(self):
- context = super(UserDetail, self).get_serializer_context() # lint-amnesty, pylint: disable=super-with-arguments
+ context = super().get_serializer_context()
context['api_version'] = self.kwargs.get('api_version')
return context
@@ -152,7 +151,7 @@ class UserCourseStatus(views.APIView):
Returns the course status
"""
path = self._last_visited_module_path(request, course)
- path_ids = [six.text_type(module.location) for module in path]
+ path_ids = [str(module.location) for module in path]
return Response({
"last_visited_module_id": path_ids[0],
"last_visited_module_path": path_ids,
@@ -312,7 +311,7 @@ class UserCourseEnrollmentsList(generics.ListAPIView):
return check_org is None or (check_org.lower() == course_org.lower())
def get_serializer_context(self):
- context = super(UserCourseEnrollmentsList, self).get_serializer_context() # lint-amnesty, pylint: disable=super-with-arguments
+ context = super().get_serializer_context()
context['api_version'] = self.kwargs.get('api_version')
return context
diff --git a/lms/djangoapps/mobile_api/utils.py b/lms/djangoapps/mobile_api/utils.py
index 07b237d206..e674df8ec6 100644
--- a/lms/djangoapps/mobile_api/utils.py
+++ b/lms/djangoapps/mobile_api/utils.py
@@ -1,7 +1,6 @@
"""
Common utility methods for Mobile APIs.
"""
-from six.moves import map
API_V05 = 'v0.5'
API_V1 = 'v1'
diff --git a/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py b/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py
index 2d6233ff5b..77fb5fcf9c 100644
--- a/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py
+++ b/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py
@@ -18,6 +18,7 @@ Or for more details::
"""
import csv
+
import click
@@ -54,7 +55,7 @@ def main(unmapped_csv):
Script removes duplicates in addition to providing sorted list of plain app names.
"""
- with open(unmapped_csv, 'r') as file:
+ with open(unmapped_csv) as file:
csv_data = file.read()
reader = csv.DictReader(csv_data.splitlines())
diff --git a/lms/djangoapps/monitoring/scripts/generate_code_owner_mappings.py b/lms/djangoapps/monitoring/scripts/generate_code_owner_mappings.py
index 78c308d4a3..2a284e5db6 100644
--- a/lms/djangoapps/monitoring/scripts/generate_code_owner_mappings.py
+++ b/lms/djangoapps/monitoring/scripts/generate_code_owner_mappings.py
@@ -12,10 +12,11 @@ Or for more details::
"""
import csv
-import click
import os
import re
+import click
+
# Maps edx-platform installed Django apps to the edx repo that contains
# the app code.
EDX_REPO_APPS = {
@@ -113,10 +114,10 @@ def main(repo_csv, app_csv, dep_csv):
print('# Do not hand edit CODE_OWNER_MAPPINGS. Generated by {}'.format(os.path.basename(__file__)))
print('CODE_OWNER_MAPPINGS:')
for owner, path_list in sorted(owner_to_paths_map.items()):
- print(" {}:".format(owner))
+ print(f" {owner}:")
path_list.sort()
for path in path_list:
- print(" - {}".format(path))
+ print(f" - {path}")
owner_with_mappings_set = set(owner_to_paths_map.keys())
print('# Do not hand edit CODE_OWNER_THEMES. Generated by {}'.format(os.path.basename(__file__)))
@@ -126,10 +127,10 @@ def main(repo_csv, app_csv, dep_csv):
# only include the theme's list of owners that have mappings
theme_owner_with_mappings_list = list(theme_owner_set & owner_with_mappings_set)
if theme_owner_with_mappings_list:
- print(" {}:".format(theme))
+ print(f" {theme}:")
theme_owner_with_mappings_list.sort()
for owner in theme_owner_with_mappings_list:
- print(" - {}".format(owner))
+ print(f" - {owner}")
def _map_repo_apps(csv_type, repo_csv, app_to_repo_map, owner_map, owner_to_paths_map):
@@ -144,7 +145,7 @@ def _map_repo_apps(csv_type, repo_csv, app_to_repo_map, owner_map, owner_to_path
owner_to_paths_map (dict): Holds results mapping owner to paths
"""
- with open(repo_csv, 'r') as file:
+ with open(repo_csv) as file:
csv_data = file.read()
reader = csv.DictReader(csv_data.splitlines())
@@ -160,14 +161,14 @@ def _map_repo_apps(csv_type, repo_csv, app_to_repo_map, owner_map, owner_to_path
owner_to_paths_map[owner] = []
owner_to_paths_map[owner].append(app)
else:
- print('WARNING: Repo {} was not found in {} csv. Needed for app {}.'.format(repo_url, csv_type, app))
+ print(f'WARNING: Repo {repo_url} was not found in {csv_type} csv. Needed for app {app}.')
def _map_edx_platform_apps(app_csv, owner_map, owner_to_paths_map):
"""
Reads CSV of edx-platform app ownership and updates mappings
"""
- with open(app_csv, 'r') as file:
+ with open(app_csv) as file:
csv_data = file.read()
reader = csv.DictReader(csv_data.splitlines())
for row in reader:
@@ -215,7 +216,7 @@ def _get_and_map_code_owner(row, owner_map):
if theme:
theme = theme.lower()
- owner = '{}-{}'.format(theme, squad) if theme else squad
+ owner = f'{theme}-{squad}' if theme else squad
theme = theme or squad
if squad not in owner_map['squad_to_theme_map']: