Ran pyupgrade on lms/djangoapps

Ran pyupgrade on lms/djangoapps/instructor_analytics
Ran pyugprade on lms/djangoapps/instructor_task
Ran pyupgrade on lms/djangoapps/learner_dashboard
This commit is contained in:
usamasadiq
2021-02-16 12:55:05 +05:00
parent ba16e05899
commit 3f1df8eb2a
39 changed files with 518 additions and 592 deletions

View File

@@ -9,7 +9,6 @@ import datetime
import json
import logging
import six
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.exceptions import ObjectDoesNotExist
@@ -18,16 +17,15 @@ from django.db.models import Count, Q # lint-amnesty, pylint: disable=unused-im
from django.urls import reverse
from edx_proctoring.api import get_exam_violation_report
from opaque_keys.edx.keys import CourseKey, UsageKey
from six import text_type
import xmodule.graders as xmgraders
from lms.djangoapps.courseware.models import StudentModule
from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAllowed
from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate
from lms.djangoapps.courseware.models import StudentModule
from lms.djangoapps.grades.api import context as grades_context
from lms.djangoapps.verify_student.services import IDVerificationService
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangolib.markup import HTML, Text
from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAllowed
log = logging.getLogger(__name__)
@@ -68,7 +66,7 @@ def issued_certificates(course_key, features):
]
"""
report_run_date = datetime.date.today().strftime(u"%B %d, %Y")
report_run_date = datetime.date.today().strftime("%B %d, %Y")
certificate_features = [x for x in CERTIFICATE_FEATURES if x in features]
generated_certificates = list(GeneratedCertificate.eligible_certificates.filter(
course_id=course_key,
@@ -117,7 +115,7 @@ def enrolled_students_features(course_key, features):
DjangoJSONEncoder().default(attr)
return attr
except TypeError:
return six.text_type(attr)
return str(attr)
def extract_student(student, features):
""" convert student to dictionary """
@@ -133,12 +131,10 @@ def enrolled_students_features(course_key, features):
meta_key = feature.split('.')[1]
meta_features.append((feature, meta_key))
student_dict = dict((feature, extract_attr(student, feature))
for feature in student_features)
student_dict = {feature: extract_attr(student, feature) for feature in student_features}
profile = student.profile
if profile is not None:
profile_dict = dict((feature, extract_attr(profile, feature))
for feature in profile_features)
profile_dict = {feature: extract_attr(profile, feature) for feature in profile_features}
student_dict.update(profile_dict)
# now fetch the requested meta fields
@@ -196,7 +192,7 @@ def list_may_enroll(course_key, features):
"""
Build dict containing information about a single student.
"""
return dict((feature, getattr(student, feature)) for feature in features)
return {feature: getattr(student, feature) for feature in features}
return [extract_student(student, features) for student in may_enroll_and_unenrolled]
@@ -211,18 +207,18 @@ def get_proctored_exam_results(course_key, features):
"""
Build dict containing information about a single student exam_attempt.
"""
proctored_exam = dict(
(feature, exam_attempt.get(feature)) for feature in features if feature in exam_attempt
)
proctored_exam = {
feature: exam_attempt.get(feature) for feature in features if feature in exam_attempt
}
for status in comment_statuses:
comment_list = exam_attempt.get(
u'{status} Comments'.format(status=status),
f'{status} Comments',
[]
)
proctored_exam.update({
u'{status} Count'.format(status=status): len(comment_list),
u'{status} Comments'.format(status=status): '; '.join(comment_list),
f'{status} Count': len(comment_list),
f'{status} Comments': '; '.join(comment_list),
})
try:
proctored_exam['track'] = course_enrollments[exam_attempt['user_id']]
@@ -267,7 +263,7 @@ def coupon_codes_features(features, coupons_list, course_id):
"""
coupon_features = [x for x in COUPON_FEATURES if x in features]
coupon_dict = dict((feature, getattr(coupon, feature)) for feature in coupon_features)
coupon_dict = {feature: getattr(coupon, feature) for feature in coupon_features}
coupon_redemptions = coupon.couponredemption_set.filter(
order__status="purchased"
)
@@ -297,7 +293,7 @@ def coupon_codes_features(features, coupons_list, course_id):
# They have not been redeemed yet
coupon_dict['expiration_date'] = coupon.display_expiry_date
coupon_dict['course_id'] = text_type(coupon_dict['course_id'])
coupon_dict['course_id'] = str(coupon_dict['course_id'])
return coupon_dict
return [extract_coupon(coupon, features) for coupon in coupons_list]
@@ -371,8 +367,8 @@ def get_response_state(response):
except TypeError:
username = response.student.username
err_msg = (
u'Error occurred while attempting to load learner state '
u'{username} for state {state}.'.format(
'Error occurred while attempting to load learner state '
'{username} for state {state}.'.format(
username=username,
state=problem_state
)
@@ -426,7 +422,7 @@ def course_registration_features(features, registration_codes, csv_type):
site_name = configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME)
registration_features = [x for x in COURSE_REGISTRATION_FEATURES if x in features]
course_registration_dict = dict((feature, getattr(registration_code, feature)) for feature in registration_features) # lint-amnesty, pylint: disable=line-too-long
course_registration_dict = {feature: getattr(registration_code, feature) for feature in registration_features} # lint-amnesty, pylint: disable=line-too-long
course_registration_dict['company_name'] = None
if registration_code.invoice_item:
course_registration_dict['company_name'] = registration_code.invoice_item.invoice.company_name
@@ -454,7 +450,7 @@ def course_registration_features(features, registration_codes, csv_type):
except ObjectDoesNotExist:
pass
course_registration_dict['course_id'] = text_type(course_registration_dict['course_id'])
course_registration_dict['course_id'] = str(course_registration_dict['course_id'])
return course_registration_dict
return [extract_course_registration(code, features, csv_type) for code in registration_codes]
@@ -477,26 +473,26 @@ def dump_grading_context(course):
msg += '\n'
msg += "Graded sections:\n"
for subgrader, category, weight in course.grader.subgraders:
msg += u" subgrader=%s, type=%s, category=%s, weight=%s\n"\
msg += " subgrader=%s, type=%s, category=%s, weight=%s\n"\
% (subgrader.__class__, subgrader.type, category, weight)
subgrader.index = 1
graders[subgrader.type] = subgrader
msg += hbar
msg += u"Listing grading context for course %s\n" % text_type(course.id)
msg += "Listing grading context for course %s\n" % str(course.id)
gcontext = grades_context.grading_context_for_course(course)
msg += "graded sections:\n"
msg += '%s\n' % list(gcontext['all_graded_subsections_by_type'].keys())
for (gsomething, gsvals) in gcontext['all_graded_subsections_by_type'].items():
msg += u"--> Section %s:\n" % (gsomething)
msg += "--> Section %s:\n" % (gsomething)
for sec in gsvals:
sdesc = sec['subsection_block']
frmat = getattr(sdesc, 'format', None)
aname = ''
if frmat in graders:
gform = graders[frmat]
aname = u'%s %02d' % (gform.short_label, gform.index)
aname = '%s %02d' % (gform.short_label, gform.index)
gform.index += 1
elif sdesc.display_name in graders:
gform = graders[sdesc.display_name]
@@ -504,7 +500,7 @@ def dump_grading_context(course):
notes = ''
if getattr(sdesc, 'score_by_attempt', False):
notes = ', score by attempt!'
msg += u" %s (format=%s, Assignment=%s%s)\n"\
msg += " %s (format=%s, Assignment=%s%s)\n"\
% (sdesc.display_name, frmat, aname, notes)
msg += "all graded blocks:\n"
msg += "length=%d\n" % gcontext['count_all_graded_blocks']

View File

@@ -7,8 +7,6 @@ Format and create csv responses
import csv
import six
from six.moves import map
from django.http import HttpResponse
@@ -24,18 +22,18 @@ def create_csv_response(filename, header, datarows):
"""
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = u'attachment; filename={0}'.format(filename)
response['Content-Disposition'] = f'attachment; filename={filename}'
csvwriter = csv.writer(
response,
dialect='excel',
quotechar='"',
quoting=csv.QUOTE_ALL)
encoded_header = [six.text_type(s) for s in header]
encoded_header = [str(s) for s in header]
csvwriter.writerow(encoded_header)
for datarow in datarows:
encoded_row = [six.text_type(s) for s in datarow]
encoded_row = [str(s) for s in datarow]
csvwriter.writerow(encoded_row)
return response

View File

@@ -1,4 +1,4 @@
u"""
"""
Profile Distributions
Aggregate sums for values of fields in students profiles.
@@ -39,7 +39,7 @@ DISPLAY_NAMES = {
}
class ProfileDistribution(object):
class ProfileDistribution:
"""
Container for profile distribution data
@@ -96,7 +96,7 @@ def profile_distribution(course_id, feature):
if feature not in AVAILABLE_PROFILE_FEATURES:
raise ValueError(
u"unsupported feature requested for distribution u'{}'".format(
"unsupported feature requested for distribution u'{}'".format(
feature)
)
@@ -152,8 +152,7 @@ def profile_distribution(course_id, feature):
# query_distribution is of the form [{'featureval': 'value1', 'featureval__count': 4},
# {'featureval': 'value2', 'featureval__count': 2}, ...]
distribution = dict((vald[feature], vald[feature + '__count'])
for vald in query_distribution)
distribution = {vald[feature]: vald[feature + '__count'] for vald in query_distribution}
# distribution is of the form {'value1': 4, 'value2': 2, ...}
# change none to no_data for valid json key

View File

@@ -4,22 +4,24 @@ Tests for instructor.basic
"""
import ddt
import datetime # lint-amnesty, pylint: disable=unused-import, wrong-import-order
import json # lint-amnesty, pylint: disable=wrong-import-order
import json
from unittest.mock import MagicMock, Mock, patch
import ddt
import pytz # lint-amnesty, pylint: disable=unused-import
from django.db.models import Q # lint-amnesty, pylint: disable=unused-import
from django.urls import reverse # lint-amnesty, pylint: disable=unused-import
from edx_proctoring.api import create_exam
from edx_proctoring.models import ProctoredExamStudentAttempt
from mock import MagicMock, Mock, patch
from opaque_keys.edx.locator import UsageKey
from six import text_type # lint-amnesty, pylint: disable=unused-import
from six.moves import range, zip
from common.djangoapps.course_modes.models import CourseMode # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.course_modes.tests.factories import CourseModeFactory # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.course_modes.tests.factories import \
CourseModeFactory # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAllowed
from common.djangoapps.student.roles import CourseSalesAdminRole # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.courseware.tests.factories import InstructorFactory
from lms.djangoapps.instructor_analytics.basic import ( # lint-amnesty, pylint: disable=unused-import
AVAILABLE_FEATURES,
@@ -32,12 +34,9 @@ from lms.djangoapps.instructor_analytics.basic import ( # lint-amnesty, pylint:
get_proctored_exam_results,
get_response_state,
list_may_enroll,
list_problem_responses,
list_problem_responses
)
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAllowed
from common.djangoapps.student.roles import CourseSalesAdminRole # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@@ -47,7 +46,7 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
""" Test basic analytics functions. """
def setUp(self):
super(TestAnalyticsBasic, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_key = self.store.make_course_key('robot', 'course', 'id')
self.users = tuple(UserFactory() for _ in range(30))
self.ces = tuple(CourseEnrollment.enroll(user, self.course_key)
@@ -55,8 +54,8 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
self.instructor = InstructorFactory(course_key=self.course_key)
for user in self.users:
user.profile.meta = json.dumps({
"position": u"edX expert {}".format(user.id),
"company": u"Open edX Inc {}".format(user.id),
"position": f"edX expert {user.id}",
"company": f"Open edX Inc {user.id}",
})
user.profile.save()
self.students_who_may_enroll = list(self.users) + [UserFactory() for _ in range(5)]
@@ -66,8 +65,8 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
)
@ddt.data(
(u'あなた', u'スの中'),
(u"ГЂіи lіиэ ъэтшээи", u"Ђэаvэи аиↁ Ђэѓэ")
('あなた', 'スの中'),
("ГЂіи lіиэ ъэтшээи", "Ђэаvэи аиↁ Ђэѓэ")
)
@ddt.unpack
def test_get_response_state_with_ora(self, files_descriptions, saved_response):
@@ -92,13 +91,13 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
relevant info (student.username and state).
"""
result = Mock(spec=['student', 'state'])
result.student.username.return_value = u'user{}'.format(result_id)
result.state.return_value = u'state{}'.format(result_id)
result.student.username.return_value = f'user{result_id}'
result.state.return_value = f'state{result_id}'
return result
# Ensure that UsageKey.from_string returns a problem key that list_problem_responses can work with
# (even when called with a dummy location):
mock_problem_key = Mock(return_value=u'')
mock_problem_key = Mock(return_value='')
mock_problem_key.course_key = self.course_key
with patch.object(UsageKey, 'from_string') as patched_from_string:
patched_from_string.return_value = mock_problem_key
@@ -135,8 +134,8 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
def test_enrolled_students_features_keys(self):
query_features = ('username', 'name', 'email', 'city', 'country',)
for user in self.users:
user.profile.city = u"Mos Eisley {}".format(user.id)
user.profile.country = u"Tatooine {}".format(user.id)
user.profile.city = f"Mos Eisley {user.id}"
user.profile.country = f"Tatooine {user.id}"
user.profile.save()
for feature in query_features:
assert feature in AVAILABLE_FEATURES
@@ -173,8 +172,8 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
assert len(userreports) == len(self.users)
for userreport in userreports:
assert set(userreport.keys()) == set(query_features)
assert userreport['meta.position'] in [u'edX expert {}'.format(user.id) for user in self.users]
assert userreport['meta.company'] in [u'Open edX Inc {}'.format(user.id) for user in self.users]
assert userreport['meta.position'] in [f"edX expert {user.id}" for user in self.users]
assert userreport['meta.company'] in [f"Open edX Inc {user.id}" for user in self.users]
def test_enrolled_students_enrollment_verification(self):
"""

View File

@@ -3,7 +3,6 @@
import pytest
from django.test import TestCase
from six.moves import range
from lms.djangoapps.instructor_analytics.csvs import create_csv_response, format_dictlist, format_instances
@@ -17,7 +16,7 @@ class TestAnalyticsCSVS(TestCase):
res = create_csv_response('robot.csv', header, datarows)
assert res['Content-Type'] == 'text/csv'
assert res['Content-Disposition'] == u'attachment; filename={0}'.format('robot.csv')
assert res['Content-Disposition'] == 'attachment; filename={}'.format('robot.csv')
assert res.content.strip().decode('utf-8') == '"Name","Email"'
def test_create_csv_response(self):
@@ -26,7 +25,7 @@ class TestAnalyticsCSVS(TestCase):
res = create_csv_response('robot.csv', header, datarows)
assert res['Content-Type'] == 'text/csv'
assert res['Content-Disposition'] == u'attachment; filename={0}'.format('robot.csv')
assert res['Content-Disposition'] == 'attachment; filename={}'.format('robot.csv')
assert res.content.strip().decode('utf-8') ==\
'"Name","Email"\r\n"Jim","jim@edy.org"\r\n"Jake","jake@edy.org"\r\n"Jeeves","jeeves@edy.org"'
@@ -36,7 +35,7 @@ class TestAnalyticsCSVS(TestCase):
res = create_csv_response('robot.csv', header, datarows)
assert res['Content-Type'] == 'text/csv'
assert res['Content-Disposition'] == u'attachment; filename={0}'.format('robot.csv')
assert res['Content-Disposition'] == 'attachment; filename={}'.format('robot.csv')
assert res.content.strip().decode('utf-8') == ''
@@ -80,7 +79,7 @@ class TestAnalyticsFormatDictlist(TestCase):
res = create_csv_response('robot.csv', header, datarows)
assert res['Content-Type'] == 'text/csv'
assert res['Content-Disposition'] == u'attachment; filename={0}'.format('robot.csv')
assert res['Content-Disposition'] == 'attachment; filename={}'.format('robot.csv')
assert res.content.strip().decode('utf-8') ==\
'"Name","Email"\r\n"Jim","jim@edy.org"\r\n"Jake","jake@edy.org"\r\n"Jeeves","jeeves@edy.org"'
@@ -88,7 +87,7 @@ class TestAnalyticsFormatDictlist(TestCase):
class TestAnalyticsFormatInstances(TestCase):
""" test format_instances method """
class TestDataClass(object):
class TestDataClass:
""" Test class to generate objects for format_instances """
def __init__(self):
self.a_var = 'aval'
@@ -101,7 +100,7 @@ class TestAnalyticsFormatInstances(TestCase):
return 'dval'
def setUp(self):
super(TestAnalyticsFormatInstances, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.instances = [self.TestDataClass() for _ in range(5)]
def test_format_instances_response(self):

View File

@@ -4,18 +4,17 @@
import pytest
from django.test import TestCase
from opaque_keys.edx.locator import CourseLocator
from six.moves import range
from lms.djangoapps.instructor_analytics.distributions import AVAILABLE_PROFILE_FEATURES, profile_distribution
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.instructor_analytics.distributions import AVAILABLE_PROFILE_FEATURES, profile_distribution
class TestAnalyticsDistributions(TestCase):
'''Test analytics distribution gathering.'''
def setUp(self):
super(TestAnalyticsDistributions, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_id = CourseLocator('robot', 'course', 'id')
self.users = [UserFactory(
@@ -78,7 +77,7 @@ class TestAnalyticsDistributionsNoData(TestCase):
'''Test analytics distribution gathering.'''
def setUp(self):
super(TestAnalyticsDistributionsNoData, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_id = CourseLocator('robot', 'course', 'id')
self.users = [UserFactory(