Merge pull request #21841 from edx/bom/student-python-3
student app: python-3 upgrade
This commit is contained in:
@@ -32,7 +32,7 @@ class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
csv_path = options['csv_path']
|
||||
with open(csv_path) as csvfile:
|
||||
with open(csv_path, 'rb') as csvfile:
|
||||
reader = unicodecsv.DictReader(csvfile)
|
||||
for row in reader:
|
||||
username = row['username']
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import six
|
||||
import unittest
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
@@ -43,10 +44,11 @@ class BulkChangeEnrollmentCSVTests(SharedModuleStoreTestCase):
|
||||
self.courses.append(course)
|
||||
self.enrollments.append(CourseEnrollment.enroll(user, course.id, mode=CourseMode.AUDIT))
|
||||
|
||||
def _write_test_csv(self, csv, lines=None):
|
||||
def _write_test_csv(self, csv, lines):
|
||||
"""Write a test csv file with the lines provided"""
|
||||
csv.write("course_id,user,mode,\n")
|
||||
csv.writelines(lines)
|
||||
csv.write(b"course_id,user,mode,\n")
|
||||
for line in lines:
|
||||
csv.write(six.b(line))
|
||||
csv.seek(0)
|
||||
return csv
|
||||
|
||||
@@ -54,7 +56,7 @@ class BulkChangeEnrollmentCSVTests(SharedModuleStoreTestCase):
|
||||
def test_user_not_exist(self):
|
||||
"""Verify that warning is logged for non existing user."""
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines="course-v1:edX+DemoX+Demo_Course,user,audit\n")
|
||||
csv = self._write_test_csv(csv, lines=["course-v1:edX+DemoX+Demo_Course,user,audit\n"])
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command("bulk_change_enrollment_csv", "--csv_file_path={}".format(csv.name))
|
||||
@@ -70,7 +72,7 @@ class BulkChangeEnrollmentCSVTests(SharedModuleStoreTestCase):
|
||||
def test_invalid_course_key(self):
|
||||
"""Verify in case of invalid course key warning is logged."""
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines="Demo_Course,river,audit\n")
|
||||
csv = self._write_test_csv(csv, lines=["Demo_Course,river,audit\n"])
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command("bulk_change_enrollment_csv", "--csv_file_path={}".format(csv.name))
|
||||
@@ -86,7 +88,7 @@ class BulkChangeEnrollmentCSVTests(SharedModuleStoreTestCase):
|
||||
def test_already_enrolled_student(self):
|
||||
""" Verify in case if a user is already enrolled warning is logged."""
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines=str(self.courses[0].id) + ",amy,audit\n")
|
||||
csv = self._write_test_csv(csv, lines=[str(self.courses[0].id) + ",amy,audit\n"])
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command("bulk_change_enrollment_csv", "--csv_file_path={}".format(csv.name))
|
||||
@@ -105,8 +107,10 @@ class BulkChangeEnrollmentCSVTests(SharedModuleStoreTestCase):
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
def test_bulk_enrollment(self):
|
||||
""" Test all users are enrolled using the command."""
|
||||
lines = (str(enrollment.course.id) + "," + str(enrollment.user.username) + ",verified\n"
|
||||
for enrollment in self.enrollments)
|
||||
lines = [
|
||||
str(enrollment.course.id) + "," + str(enrollment.user.username) + ",verified\n"
|
||||
for enrollment in self.enrollments
|
||||
]
|
||||
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines=lines)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import six
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from django.core.management import call_command
|
||||
@@ -38,17 +39,18 @@ class BulkUnenrollTests(SharedModuleStoreTestCase):
|
||||
self.users.append(user)
|
||||
self.enrollments.append(CourseEnrollment.enroll(user, self.course.id, mode='audit'))
|
||||
|
||||
def _write_test_csv(self, csv, lines=None):
|
||||
"""Write a test csv file with the lines procided"""
|
||||
csv.write("user_id,username,email,course_id\n")
|
||||
csv.writelines(lines)
|
||||
def _write_test_csv(self, csv, lines):
|
||||
"""Write a test csv file with the lines provided"""
|
||||
csv.write(b"user_id,username,email,course_id\n")
|
||||
for line in lines:
|
||||
csv.write(six.b(line))
|
||||
csv.seek(0)
|
||||
return csv
|
||||
|
||||
def test_user_not_exist(self):
|
||||
"""Verify that warning user not exist is logged for non existing user."""
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines="111,test,test@example.com,course-v1:edX+DemoX+Demo_Course\n")
|
||||
csv = self._write_test_csv(csv, lines=["111,test,test@example.com,course-v1:edX+DemoX+Demo_Course\n"])
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command("bulk_unenroll", "--csv_path={}".format(csv.name))
|
||||
@@ -63,7 +65,7 @@ class BulkUnenrollTests(SharedModuleStoreTestCase):
|
||||
def test_invalid_course_key(self):
|
||||
"""Verify in case of invalid course key warning is logged."""
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines="111,amy,amy@pond.com,test_course\n")
|
||||
csv = self._write_test_csv(csv, lines=["111,amy,amy@pond.com,test_course\n"])
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command("bulk_unenroll", "--csv_path={}".format(csv.name))
|
||||
@@ -79,7 +81,7 @@ class BulkUnenrollTests(SharedModuleStoreTestCase):
|
||||
def test_user_not_enrolled(self):
|
||||
"""Verify in case of user not enrolled in course warning is logged."""
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines="111,amy,amy@pond.com,course-v1:edX+DemoX+Demo_Course\n")
|
||||
csv = self._write_test_csv(csv, lines=["111,amy,amy@pond.com,course-v1:edX+DemoX+Demo_Course\n"])
|
||||
|
||||
with LogCapture(LOGGER_NAME) as log:
|
||||
call_command("bulk_unenroll", "--csv_path={}".format(csv.name))
|
||||
@@ -94,11 +96,13 @@ class BulkUnenrollTests(SharedModuleStoreTestCase):
|
||||
|
||||
def test_bulk_un_enroll(self):
|
||||
"""Verify users are unenrolled using the command."""
|
||||
lines = (str(enrollment.user.id) + "," + enrollment.user.username + "," +
|
||||
enrollment.user.email + "," + str(enrollment.course.id) + "\n"
|
||||
for enrollment in self.enrollments)
|
||||
lines = [
|
||||
str(enrollment.user.id) + "," + enrollment.user.username + "," +
|
||||
enrollment.user.email + "," + str(enrollment.course.id) + "\n"
|
||||
for enrollment in self.enrollments
|
||||
]
|
||||
with NamedTemporaryFile() as csv:
|
||||
csv = self._write_test_csv(csv, lines=lines)\
|
||||
csv = self._write_test_csv(csv, lines=lines)
|
||||
|
||||
call_command("bulk_unenroll", "--csv_path={}".format(csv.name))
|
||||
for enrollment in CourseEnrollment.objects.all():
|
||||
|
||||
@@ -58,13 +58,13 @@ class TestStudentDashboardEmailView(SharedModuleStoreTestCase):
|
||||
BulkEmailFlag.objects.create(enabled=True, require_course_email_auth=False)
|
||||
# Assert that the URL for the email view is in the response
|
||||
response = self.client.get(self.url)
|
||||
self.assertIn(self.email_modal_link, response.content)
|
||||
self.assertContains(response, self.email_modal_link)
|
||||
|
||||
def test_email_flag_false(self):
|
||||
BulkEmailFlag.objects.create(enabled=False)
|
||||
# Assert that the URL for the email view is not in the response
|
||||
response = self.client.get(self.url)
|
||||
self.assertNotIn(self.email_modal_link, response.content)
|
||||
self.assertNotContains(response, self.email_modal_link)
|
||||
|
||||
def test_email_unauthorized(self):
|
||||
BulkEmailFlag.objects.create(enabled=True, require_course_email_auth=True)
|
||||
@@ -73,7 +73,7 @@ class TestStudentDashboardEmailView(SharedModuleStoreTestCase):
|
||||
# Assert that the URL for the email view is not in the response
|
||||
# if this course isn't authorized
|
||||
response = self.client.get(self.url)
|
||||
self.assertNotIn(self.email_modal_link, response.content)
|
||||
self.assertNotContains(response, self.email_modal_link)
|
||||
|
||||
def test_email_authorized(self):
|
||||
BulkEmailFlag.objects.create(enabled=True, require_course_email_auth=True)
|
||||
@@ -85,4 +85,4 @@ class TestStudentDashboardEmailView(SharedModuleStoreTestCase):
|
||||
# Assert that the URL for the email view is not in the response
|
||||
# if this course isn't authorized
|
||||
response = self.client.get(self.url)
|
||||
self.assertIn(self.email_modal_link, response.content)
|
||||
self.assertContains(response, self.email_modal_link)
|
||||
|
||||
@@ -299,7 +299,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
|
||||
self._assert_course_verification_status(VERIFY_STATUS_APPROVED)
|
||||
response2 = self.client.get(self.dashboard_url)
|
||||
self.assertContains(response2, attempt2.expiration_datetime.strftime("%m/%d/%Y"))
|
||||
self.assertEqual(response2.content.count(attempt2.expiration_datetime.strftime("%m/%d/%Y")), 2)
|
||||
self.assertContains(response2, attempt2.expiration_datetime.strftime("%m/%d/%Y"), count=2)
|
||||
|
||||
def _setup_mode_and_enrollment(self, deadline, enrollment_mode):
|
||||
"""Create a course mode and enrollment.
|
||||
@@ -383,7 +383,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
|
||||
# and fail if none of these are found.
|
||||
found_msg = False
|
||||
for message in self.NOTIFICATION_MESSAGES[status]:
|
||||
if message in response.content:
|
||||
if six.b(message) in response.content:
|
||||
found_msg = True
|
||||
break
|
||||
|
||||
|
||||
@@ -263,11 +263,11 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
|
||||
set_prerequisite_courses(self.course.id, [six.text_type(self.pre_requisite_course.id)])
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('<div class="prerequisites">', response.content)
|
||||
self.assertContains(response, '<div class="prerequisites">')
|
||||
|
||||
remove_prerequisite_course(self.course.id, get_course_milestones(self.course.id)[0])
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertNotIn('<div class="prerequisites">', response.content)
|
||||
self.assertNotContains(response, '<div class="prerequisites">')
|
||||
|
||||
@patch('openedx.core.djangoapps.programs.utils.get_programs')
|
||||
@patch('student.views.dashboard.get_visible_sessions_for_entitlement')
|
||||
@@ -301,10 +301,10 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
'type': 'verified'
|
||||
}
|
||||
response = self.client.get(self.path)
|
||||
self.assertIn('class="course-target-link enter-course hidden"', response.content)
|
||||
self.assertIn('You must select a session to access the course.', response.content)
|
||||
self.assertIn('<div class="course-entitlement-selection-container ">', response.content)
|
||||
self.assertIn('Related Programs:', response.content)
|
||||
self.assertContains(response, 'class="course-target-link enter-course hidden"')
|
||||
self.assertContains(response, 'You must select a session to access the course.')
|
||||
self.assertContains(response, '<div class="course-entitlement-selection-container ">')
|
||||
self.assertContains(response, 'Related Programs:')
|
||||
|
||||
# If an entitlement has already been redeemed by the user for a course run, do not let the run be selectable
|
||||
enrollment = CourseEnrollmentFactory(
|
||||
@@ -326,9 +326,9 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
response = self.client.get(self.path)
|
||||
# There should be two entitlements on the course page, one prompting for a mandatory session, but no
|
||||
# select option for the courses as there is only the single course run which has already been redeemed
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 2)
|
||||
self.assertIn('You must select a session to access the course.', response.content)
|
||||
self.assertNotIn('To access the course, select a session.', response.content)
|
||||
self.assertContains(response, '<li class="course-item">', count=2)
|
||||
self.assertContains(response, 'You must select a session to access the course.')
|
||||
self.assertNotContains(response, 'To access the course, select a session.')
|
||||
|
||||
@patch('student.views.dashboard.get_visible_sessions_for_entitlement')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
@@ -354,7 +354,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
}
|
||||
]
|
||||
response = self.client.get(self.path)
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 0)
|
||||
self.assertNotContains(response, '<li class="course-item">')
|
||||
|
||||
@patch('entitlements.api.v1.views.get_course_runs_for_course')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
@@ -454,9 +454,9 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
program['courses'][0]['uuid'] = entitlement.course_uuid
|
||||
mock_get_programs.return_value = [program]
|
||||
response = self.client.get(self.path)
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 1)
|
||||
self.assertIn('<button class="change-session btn-link "', response.content)
|
||||
self.assertIn('Related Programs:', response.content)
|
||||
self.assertContains(response, '<li class="course-item">', count=1)
|
||||
self.assertContains(response, '<button class="change-session btn-link "')
|
||||
self.assertContains(response, 'Related Programs:')
|
||||
|
||||
@patch('openedx.core.djangoapps.programs.utils.get_programs')
|
||||
@patch('student.views.dashboard.get_visible_sessions_for_entitlement')
|
||||
@@ -489,9 +489,9 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
program['courses'][0]['uuid'] = entitlement.course_uuid
|
||||
mock_get_programs.return_value = [program]
|
||||
response = self.client.get(self.path)
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 1)
|
||||
self.assertIn('You can no longer change sessions.', response.content)
|
||||
self.assertIn('Related Programs:', response.content)
|
||||
self.assertContains(response, '<li class="course-item">', count=1)
|
||||
self.assertContains(response, 'You can no longer change sessions.')
|
||||
self.assertContains(response, 'Related Programs:')
|
||||
|
||||
@patch('openedx.core.djangoapps.catalog.utils.get_course_runs_for_course')
|
||||
@patch('student.views.dashboard.is_bulk_email_feature_enabled')
|
||||
@@ -535,13 +535,13 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
# Ensure active users see the course list
|
||||
self.assertTrue(self.user.is_active)
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('You are not enrolled in any courses yet.', response.content)
|
||||
self.assertContains(response, 'You are not enrolled in any courses yet.')
|
||||
|
||||
# Ensure inactive users don't see the course list
|
||||
self.user.is_active = False
|
||||
self.user.save()
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertNotIn('You are not enrolled in any courses yet.', response.content)
|
||||
self.assertNotContains(response, 'You are not enrolled in any courses yet.')
|
||||
|
||||
def test_show_empty_dashboard_message(self):
|
||||
"""
|
||||
@@ -550,15 +550,15 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
"""
|
||||
empty_dashboard_message = "Check out our lovely <i>free</i> courses!"
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('You are not enrolled in any courses yet.', response.content)
|
||||
self.assertNotIn(empty_dashboard_message, response.content)
|
||||
self.assertContains(response, 'You are not enrolled in any courses yet.')
|
||||
self.assertNotContains(response, empty_dashboard_message)
|
||||
|
||||
with with_site_configuration_context(configuration={
|
||||
"EMPTY_DASHBOARD_MESSAGE": empty_dashboard_message,
|
||||
}):
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('You are not enrolled in any courses yet.', response.content)
|
||||
self.assertIn(empty_dashboard_message, response.content)
|
||||
self.assertContains(response, 'You are not enrolled in any courses yet.')
|
||||
self.assertContains(response, empty_dashboard_message)
|
||||
|
||||
@patch('django.conf.settings.DASHBOARD_COURSE_LIMIT', 1)
|
||||
def test_course_limit_on_dashboard(self):
|
||||
@@ -575,12 +575,16 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
)
|
||||
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('1 results successfully populated', response.content)
|
||||
self.assertContains(response, '1 results successfully populated')
|
||||
|
||||
@staticmethod
|
||||
def _remove_whitespace_from_html_string(html):
|
||||
return ''.join(html.split())
|
||||
|
||||
@staticmethod
|
||||
def _remove_whitespace_from_response(response):
|
||||
return ''.join(response.content.decode('utf-8').split())
|
||||
|
||||
@staticmethod
|
||||
def _pull_course_run_from_course_key(course_key_string):
|
||||
search_results = re.search(r'Run_[0-9]+$', course_key_string)
|
||||
@@ -665,7 +669,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
|
||||
view_button_html = self._remove_whitespace_from_html_string(view_button_html)
|
||||
resume_button_html = self._remove_whitespace_from_html_string(resume_button_html)
|
||||
dashboard_html = self._remove_whitespace_from_html_string(response.content)
|
||||
dashboard_html = self._remove_whitespace_from_response(response)
|
||||
|
||||
self.assertIn(
|
||||
view_button_html,
|
||||
@@ -719,7 +723,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
|
||||
view_button_html = self._remove_whitespace_from_html_string(view_button_html)
|
||||
resume_button_html = self._remove_whitespace_from_html_string(resume_button_html)
|
||||
dashboard_html = self._remove_whitespace_from_html_string(response.content)
|
||||
dashboard_html = self._remove_whitespace_from_response(response)
|
||||
|
||||
self.assertIn(
|
||||
resume_button_html,
|
||||
@@ -749,7 +753,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
schedule = ScheduleFactory(start=self.THREE_YEARS_AGO + timedelta(days=1), enrollment=enrollment)
|
||||
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
dashboard_html = self._remove_whitespace_from_html_string(response.content.decode('utf-8'))
|
||||
dashboard_html = self._remove_whitespace_from_response(response)
|
||||
access_expired_substring = 'Accessexpired'
|
||||
course_link_class = 'course-target-link'
|
||||
|
||||
@@ -848,7 +852,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
for button in html_for_entitlement
|
||||
]
|
||||
|
||||
dashboard_html = self._remove_whitespace_from_html_string(response.content)
|
||||
dashboard_html = self._remove_whitespace_from_response(response)
|
||||
|
||||
for i in range(num_course_cards):
|
||||
expected_button = None
|
||||
|
||||
@@ -433,13 +433,13 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
response = self.client.get(redeem_url)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
# check button text
|
||||
self.assertIn('Activate Course Enrollment', response.content)
|
||||
self.assertContains(response, 'Activate Course Enrollment')
|
||||
|
||||
#now activate the user by enrolling him/her to the course
|
||||
response = self.client.post(redeem_url)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('You can no longer access this course because payment has not yet been received', response.content)
|
||||
self.assertContains(response, 'You can no longer access this course because payment has not yet been received')
|
||||
optout_object = Optout.objects.filter(user=self.user, course_id=self.course.id)
|
||||
self.assertEqual(len(optout_object), 1)
|
||||
|
||||
@@ -457,7 +457,10 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
invoice.save()
|
||||
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertNotIn('You can no longer access this course because payment has not yet been received', response.content)
|
||||
self.assertNotContains(
|
||||
response,
|
||||
'You can no longer access this course because payment has not yet been received',
|
||||
)
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
def test_linked_in_add_to_profile_btn_not_appearing_without_config(self):
|
||||
@@ -490,7 +493,7 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertNotIn('Add Certificate to LinkedIn', response.content)
|
||||
self.assertNotContains(response, 'Add Certificate to LinkedIn')
|
||||
|
||||
response_url = 'http://www.linkedin.com/profile/add?_ed='
|
||||
self.assertNotContains(response, escape(response_url))
|
||||
@@ -534,7 +537,7 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertIn('Add Certificate to LinkedIn', response.content)
|
||||
self.assertContains(response, 'Add Certificate to LinkedIn')
|
||||
|
||||
expected_url = (
|
||||
u'http://www.linkedin.com/profile/add'
|
||||
|
||||
Reference in New Issue
Block a user