diff --git a/lms/djangoapps/instructor_analytics/basic.py b/lms/djangoapps/instructor_analytics/basic.py index 413c80e614..4ebc3093b2 100644 --- a/lms/djangoapps/instructor_analytics/basic.py +++ b/lms/djangoapps/instructor_analytics/basic.py @@ -3,21 +3,24 @@ Student and course analytics. Serve miscellaneous course and student data """ +from __future__ import absolute_import + import datetime import json +import six from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.core.serializers.json import DjangoJSONEncoder -from django.urls import reverse from django.db.models import Count, Q +from django.urls import reverse from edx_proctoring.api import get_exam_violation_report from opaque_keys.edx.keys import UsageKey from six import text_type -from courseware.models import StudentModule import xmodule.graders as xmgraders +from courseware.models import StudentModule from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate from lms.djangoapps.grades.api import context as grades_context from lms.djangoapps.verify_student.services import IDVerificationService @@ -114,7 +117,7 @@ def sale_order_record_features(course_id, features): coupon_codes = [redemption.coupon.code for redemption in coupon_redemption] order_item_dict.update({'coupon_code': ", ".join(coupon_codes)}) - sale_order_dict.update(dict(order_item_dict.items())) + sale_order_dict.update(dict(list(order_item_dict.items()))) return sale_order_dict @@ -172,7 +175,7 @@ def sale_record_features(course_id, features): course_reg_dict['course_id'] = text_type(course_id) course_reg_dict.update({'codes': ", ".join(codes)}) - sale_dict.update(dict(course_reg_dict.items())) + sale_dict.update(dict(list(course_reg_dict.items()))) return sale_dict @@ -240,7 +243,7 @@ def enrolled_students_features(course_key, features): DjangoJSONEncoder().default(attr) return attr except TypeError: - return unicode(attr) + return six.text_type(attr) def extract_student(student, features): """ convert student to dictionary """ @@ -528,7 +531,7 @@ def dump_grading_context(course): gcontext = grades_context.grading_context_for_course(course) msg += "graded sections:\n" - msg += '%s\n' % gcontext['all_graded_subsections_by_type'].keys() + 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) for sec in gsvals: diff --git a/lms/djangoapps/instructor_analytics/csvs.py b/lms/djangoapps/instructor_analytics/csvs.py index 30a5214faf..a5ca1c5f6e 100644 --- a/lms/djangoapps/instructor_analytics/csvs.py +++ b/lms/djangoapps/instructor_analytics/csvs.py @@ -4,8 +4,12 @@ Student and course analytics. Format and create csv responses """ +from __future__ import absolute_import + import csv +import six +from six.moves import map from django.http import HttpResponse @@ -28,11 +32,11 @@ def create_csv_response(filename, header, datarows): quotechar='"', quoting=csv.QUOTE_ALL) - encoded_header = [unicode(s).encode('utf-8') for s in header] + encoded_header = [six.text_type(s).encode('utf-8') for s in header] csvwriter.writerow(encoded_header) for datarow in datarows: - encoded_row = [unicode(s).encode('utf-8') for s in datarow] + encoded_row = [six.text_type(s).encode('utf-8') for s in datarow] csvwriter.writerow(encoded_row) return response @@ -79,7 +83,7 @@ def format_dictlist(dictlist, features): return vals header = features - datarows = map(dict_to_entry, dictlist) + datarows = list(map(dict_to_entry, dictlist)) return header, datarows diff --git a/lms/djangoapps/instructor_analytics/distributions.py b/lms/djangoapps/instructor_analytics/distributions.py index 93d1c9bcb2..697b59cb65 100644 --- a/lms/djangoapps/instructor_analytics/distributions.py +++ b/lms/djangoapps/instructor_analytics/distributions.py @@ -21,6 +21,8 @@ The distribution in a course for gender might look like: } """ +from __future__ import absolute_import + from django.db.models import Count from student.models import CourseEnrollment, UserProfile diff --git a/lms/djangoapps/instructor_analytics/tests/test_basic.py b/lms/djangoapps/instructor_analytics/tests/test_basic.py index 99ccccd747..46a8810c89 100644 --- a/lms/djangoapps/instructor_analytics/tests/test_basic.py +++ b/lms/djangoapps/instructor_analytics/tests/test_basic.py @@ -2,17 +2,20 @@ Tests for instructor.basic """ +from __future__ import absolute_import + import datetime import json import pytz -from django.urls import reverse from django.db.models import Q +from django.urls import reverse 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 +from six.moves import range, zip from course_modes.models import CourseMode from course_modes.tests.factories import CourseModeFactory @@ -55,7 +58,7 @@ class TestAnalyticsBasic(ModuleStoreTestCase): def setUp(self): super(TestAnalyticsBasic, self).setUp() self.course_key = self.store.make_course_key('robot', 'course', 'id') - self.users = tuple(UserFactory() for _ in xrange(30)) + self.users = tuple(UserFactory() for _ in range(30)) self.ces = tuple(CourseEnrollment.enroll(user, self.course_key) for user in self.users) self.instructor = InstructorFactory(course_key=self.course_key) @@ -118,7 +121,7 @@ class TestAnalyticsBasic(ModuleStoreTestCase): userreports = enrolled_students_features(self.course_key, ['username']) self.assertEqual(len(userreports), len(self.users)) for userreport in userreports: - self.assertEqual(userreport.keys(), ['username']) + self.assertEqual(list(userreport.keys()), ['username']) self.assertIn(userreport['username'], [user.username for user in self.users]) def test_enrolled_students_features_keys(self): @@ -197,7 +200,7 @@ class TestAnalyticsBasic(ModuleStoreTestCase): course = CourseFactory.create(org="test", course="course1", display_name="run1") course.cohort_config = {'cohorted': True, 'auto_cohort': True, 'auto_cohort_groups': ['cohort']} self.store.update_item(course, self.instructor.id) - cohorted_students = [UserFactory.create() for _ in xrange(10)] + cohorted_students = [UserFactory.create() for _ in range(10)] cohort = CohortFactory.create(name='cohort', course_id=course.id, users=cohorted_students) cohorted_usernames = [student.username for student in cohorted_students] non_cohorted_student = UserFactory.create() @@ -233,7 +236,7 @@ class TestAnalyticsBasic(ModuleStoreTestCase): self.assertEqual(len(may_enroll), len(self.students_who_may_enroll) - len(self.users)) email_adresses = [student.email for student in self.students_who_may_enroll] for student in may_enroll: - self.assertEqual(student.keys(), ['email']) + self.assertEqual(list(student.keys()), ['email']) self.assertIn(student['email'], email_adresses) def test_get_student_exam_attempt_features(self): diff --git a/lms/djangoapps/instructor_analytics/tests/test_csvs.py b/lms/djangoapps/instructor_analytics/tests/test_csvs.py index 5fc2de30c1..c943619fec 100644 --- a/lms/djangoapps/instructor_analytics/tests/test_csvs.py +++ b/lms/djangoapps/instructor_analytics/tests/test_csvs.py @@ -1,7 +1,10 @@ """ Tests for analytics.csvs """ +from __future__ import absolute_import + import pytest from django.test import TestCase +from six.moves import range from instructor_analytics.csvs import create_csv_response, format_dictlist, format_instances @@ -98,7 +101,7 @@ class TestAnalyticsFormatInstances(TestCase): def setUp(self): super(TestAnalyticsFormatInstances, self).setUp() - self.instances = [self.TestDataClass() for _ in xrange(5)] + self.instances = [self.TestDataClass() for _ in range(5)] def test_format_instances_response(self): features = ['a_var', 'c_var', 'd_var'] @@ -108,7 +111,7 @@ class TestAnalyticsFormatInstances(TestCase): 'aval', 'cval', 'dval', - ] for _ in xrange(len(self.instances))]) + ] for _ in range(len(self.instances))]) def test_format_instances_response_noinstances(self): features = ['a_var'] @@ -119,7 +122,7 @@ class TestAnalyticsFormatInstances(TestCase): def test_format_instances_response_nofeatures(self): header, datarows = format_instances(self.instances, []) self.assertEqual(header, []) - self.assertEqual(datarows, [[] for _ in xrange(len(self.instances))]) + self.assertEqual(datarows, [[] for _ in range(len(self.instances))]) def test_format_instances_response_nonexistantfeature(self): with pytest.raises(AttributeError): diff --git a/lms/djangoapps/instructor_analytics/tests/test_distributions.py b/lms/djangoapps/instructor_analytics/tests/test_distributions.py index ff57ac6822..ad3a829642 100644 --- a/lms/djangoapps/instructor_analytics/tests/test_distributions.py +++ b/lms/djangoapps/instructor_analytics/tests/test_distributions.py @@ -1,9 +1,10 @@ """ Tests for analytics.distributions """ -from __future__ import print_function +from __future__ import absolute_import, print_function import pytest from django.test import TestCase from opaque_keys.edx.locator import CourseLocator +from six.moves import range from instructor_analytics.distributions import AVAILABLE_PROFILE_FEATURES, profile_distribution from student.models import CourseEnrollment @@ -21,7 +22,7 @@ class TestAnalyticsDistributions(TestCase): profile__gender=['m', 'f', 'o'][i % 3], profile__level_of_education=['a', 'hs', 'el'][i % 3], profile__year_of_birth=i + 1930 - ) for i in xrange(30)] + ) for i in range(30)] self.ces = [CourseEnrollment.enroll(user, self.course_id) for user in self.users] @@ -82,12 +83,12 @@ class TestAnalyticsDistributionsNoData(TestCase): self.users = [UserFactory( profile__year_of_birth=i + 1930, - ) for i in xrange(5)] + ) for i in range(5)] self.nodata_users = [UserFactory( profile__year_of_birth=None, profile__gender=[None, ''][i % 2] - ) for i in xrange(4)] + ) for i in range(4)] self.users += self.nodata_users