Commit 61d247d4 by J. Cliff Dyer

Prefer iters and sets to lists

parent 3278fcf1
...@@ -17,11 +17,11 @@ from common.test.utils import XssTestMixin ...@@ -17,11 +17,11 @@ from common.test.utils import XssTestMixin
from xmodule.course_module import CourseSummary from xmodule.course_module import CourseSummary
from contentstore.views.course import ( from contentstore.views.course import (
_accessible_courses_list, _accessible_courses_iter,
_accessible_courses_list_from_groups, _accessible_courses_list_from_groups,
AccessListFallback, AccessListFallback,
get_courses_accessible_to_user, get_courses_accessible_to_user,
_accessible_courses_summary_list, _accessible_courses_summary_iter,
) )
from contentstore.utils import delete_course_and_groups from contentstore.utils import delete_course_and_groups
from contentstore.tests.utils import AjaxEnabledTestClient from contentstore.tests.utils import AjaxEnabledTestClient
...@@ -132,11 +132,12 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -132,11 +132,12 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self._create_course_with_access_groups(course_location, self.user) self._create_course_with_access_groups(course_location, self.user)
# get courses through iterating all courses # get courses through iterating all courses
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
courses_list = list(courses_iter)
self.assertEqual(len(courses_list), 1) self.assertEqual(len(courses_list), 1)
courses_summary_list, __ = _accessible_courses_summary_list(self.request) courses_summary_list, __ = _accessible_courses_summary_iter(self.request)
self.assertEqual(len(courses_summary_list), 1) self.assertEqual(len(list(courses_summary_list)), 1)
# get courses by reversing group name formats # get courses by reversing group name formats
courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request) courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
...@@ -179,8 +180,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -179,8 +180,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# Verify that CCX courses are filtered out while iterating over all courses # Verify that CCX courses are filtered out while iterating over all courses
mocked_ccx_course = Mock(id=ccx_course_key) mocked_ccx_course = Mock(id=ccx_course_key)
with patch('xmodule.modulestore.mixed.MixedModuleStore.get_courses', return_value=[mocked_ccx_course]): with patch('xmodule.modulestore.mixed.MixedModuleStore.get_courses', return_value=[mocked_ccx_course]):
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
self.assertEqual(len(courses_list), 0) self.assertEqual(len(list(courses_iter)), 0)
@ddt.data( @ddt.data(
(ModuleStoreEnum.Type.split, 'xmodule.modulestore.split_mongo.split_mongo_kvs.SplitMongoKVS'), (ModuleStoreEnum.Type.split, 'xmodule.modulestore.split_mongo.split_mongo_kvs.SplitMongoKVS'),
...@@ -201,8 +202,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -201,8 +202,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self.assertIsInstance(self.store.get_course(course_key), ErrorDescriptor) self.assertIsInstance(self.store.get_course(course_key), ErrorDescriptor)
# get courses through iterating all courses # get courses through iterating all courses
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
self.assertEqual(courses_list, []) self.assertEqual(list(courses_iter), [])
# get courses by reversing group name formats # get courses by reversing group name formats
courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request) courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
...@@ -231,14 +232,14 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -231,14 +232,14 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# Fetch accessible courses list & verify their count # Fetch accessible courses list & verify their count
courses_list_by_staff, __ = get_courses_accessible_to_user(self.request) courses_list_by_staff, __ = get_courses_accessible_to_user(self.request)
self.assertEqual(len(courses_list_by_staff), TOTAL_COURSES_COUNT) self.assertEqual(len(list(courses_list_by_staff)), TOTAL_COURSES_COUNT)
# Verify fetched accessible courses list is a list of CourseSummery instances # Verify fetched accessible courses list is a list of CourseSummery instances
self.assertTrue(all(isinstance(course, CourseSummary) for course in courses_list_by_staff)) self.assertTrue(all(isinstance(course, CourseSummary) for course in courses_list_by_staff))
# Now count the db queries for staff # Now count the db queries for staff
with check_mongo_calls(mongo_calls): with check_mongo_calls(mongo_calls):
_accessible_courses_summary_list(self.request) list(_accessible_courses_summary_iter(self.request))
@ddt.data( @ddt.data(
(ModuleStoreEnum.Type.split, 'xmodule.modulestore.split_mongo.split_mongo_kvs.SplitMongoKVS'), (ModuleStoreEnum.Type.split, 'xmodule.modulestore.split_mongo.split_mongo_kvs.SplitMongoKVS'),
...@@ -261,7 +262,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -261,7 +262,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self.assertIsInstance(self.store.get_course(course_key), ErrorDescriptor) self.assertIsInstance(self.store.get_course(course_key), ErrorDescriptor)
# get courses through iterating all courses # get courses through iterating all courses
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
courses_list = list(courses_iter)
self.assertEqual(courses_list, []) self.assertEqual(courses_list, [])
# get courses by reversing group name formats # get courses by reversing group name formats
...@@ -279,10 +281,12 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -279,10 +281,12 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self._create_course_with_access_groups(course_key, self.user, store) self._create_course_with_access_groups(course_key, self.user, store)
# get courses through iterating all courses # get courses through iterating all courses
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
courses_list = list(courses_iter)
self.assertEqual(len(courses_list), 1) self.assertEqual(len(courses_list), 1)
courses_summary_list, __ = _accessible_courses_summary_list(self.request) courses_summary_iter, __ = _accessible_courses_summary_iter(self.request)
courses_summary_list = list(courses_summary_iter)
# Verify fetched accessible courses list is a list of CourseSummery instances and only one course # Verify fetched accessible courses list is a list of CourseSummery instances and only one course
# is returned # is returned
...@@ -302,17 +306,17 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -302,17 +306,17 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
CourseInstructorRole(course_key).add_users(self.user) CourseInstructorRole(course_key).add_users(self.user)
# Get courses through iterating all courses # Get courses through iterating all courses
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
# Get course summaries by iterating all courses # Get course summaries by iterating all courses
courses_summary_list, __ = _accessible_courses_summary_list(self.request) courses_summary_iter, __ = _accessible_courses_summary_iter(self.request)
# Get courses by reversing group name formats # Get courses by reversing group name formats
courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request) courses_list_by_groups, __ = _accessible_courses_list_from_groups(self.request)
# Test that course list returns no course # Test that course list returns no course
self.assertEqual( self.assertEqual(
[len(courses_list), len(courses_list_by_groups), len(courses_summary_list)], [len(list(courses_iter)), len(courses_list_by_groups), len(list(courses_summary_iter))],
[0, 0, 0] [0, 0, 0]
) )
...@@ -344,13 +348,13 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -344,13 +348,13 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# time the get courses by iterating through all courses # time the get courses by iterating through all courses
with Timer() as iteration_over_courses_time_1: with Timer() as iteration_over_courses_time_1:
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
self.assertEqual(len(courses_list), USER_COURSES_COUNT) self.assertEqual(len(list(courses_iter)), USER_COURSES_COUNT)
# time again the get courses by iterating through all courses # time again the get courses by iterating through all courses
with Timer() as iteration_over_courses_time_2: with Timer() as iteration_over_courses_time_2:
courses_list, __ = _accessible_courses_list(self.request) courses_iter, __ = _accessible_courses_iter(self.request)
self.assertEqual(len(courses_list), USER_COURSES_COUNT) self.assertEqual(len(list(courses_iter)), USER_COURSES_COUNT)
# time the get courses by reversing django groups # time the get courses by reversing django groups
with Timer() as iteration_over_groups_time_1: with Timer() as iteration_over_groups_time_1:
...@@ -372,7 +376,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -372,7 +376,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
_accessible_courses_list_from_groups(self.request) _accessible_courses_list_from_groups(self.request)
with check_mongo_calls(courses_list_calls): with check_mongo_calls(courses_list_calls):
_accessible_courses_list(self.request) list(_accessible_courses_iter(self.request))
# Calls: # Calls:
# 1) query old mongo # 1) query old mongo
# 2) get_more on old mongo # 2) get_more on old mongo
...@@ -424,7 +428,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -424,7 +428,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# Verify fetched accessible courses list is a list of CourseSummery instances and test expacted # Verify fetched accessible courses list is a list of CourseSummery instances and test expacted
# course count is returned # course count is returned
self.assertEqual(len(courses_list), 2) self.assertEqual(len(list(courses_list)), 2)
self.assertTrue(all(isinstance(course, CourseSummary) for course in courses_list)) self.assertTrue(all(isinstance(course, CourseSummary) for course in courses_list))
def test_course_listing_with_actions_in_progress(self): def test_course_listing_with_actions_in_progress(self):
...@@ -447,7 +451,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin): ...@@ -447,7 +451,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
) )
# verify return values # verify return values
for method in (_accessible_courses_list_from_groups, _accessible_courses_list): for method in (_accessible_courses_list_from_groups, _accessible_courses_iter):
def set_of_course_keys(course_list, key_attribute_name='id'): def set_of_course_keys(course_list, key_attribute_name='id'):
"""Returns a python set of course keys by accessing the key with the given attribute name.""" """Returns a python set of course keys by accessing the key with the given attribute name."""
return set(getattr(c, key_attribute_name) for c in course_list) return set(getattr(c, key_attribute_name) for c in course_list)
......
...@@ -17,6 +17,7 @@ import django.utils ...@@ -17,6 +17,7 @@ import django.utils
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.decorators.http import require_http_methods, require_GET from django.views.decorators.http import require_http_methods, require_GET
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
import six
from opaque_keys import InvalidKeyError from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
...@@ -357,13 +358,14 @@ def get_in_process_course_actions(request): ...@@ -357,13 +358,14 @@ def get_in_process_course_actions(request):
return [ return [
course for course in course for course in
CourseRerunState.objects.find_all( CourseRerunState.objects.find_all(
exclude_args={'state': CourseRerunUIStateManager.State.SUCCEEDED}, should_display=True exclude_args={'state': CourseRerunUIStateManager.State.SUCCEEDED},
should_display=True,
) )
if has_studio_read_access(request.user, course.course_key) if has_studio_read_access(request.user, course.course_key)
] ]
def _accessible_courses_summary_list(request): def _accessible_courses_summary_iter(request):
""" """
List all courses available to the logged in user by iterating through all the courses List all courses available to the logged in user by iterating through all the courses
""" """
...@@ -378,12 +380,12 @@ def _accessible_courses_summary_list(request): ...@@ -378,12 +380,12 @@ def _accessible_courses_summary_list(request):
return has_studio_read_access(request.user, course_summary.id) return has_studio_read_access(request.user, course_summary.id)
courses_summary = filter(course_filter, modulestore().get_course_summaries()) courses_summary = six.moves.filter(course_filter, modulestore().get_course_summaries())
in_process_course_actions = get_in_process_course_actions(request) in_process_course_actions = get_in_process_course_actions(request)
return courses_summary, in_process_course_actions return courses_summary, in_process_course_actions
def _accessible_courses_list(request): def _accessible_courses_iter(request):
""" """
List all courses available to the logged in user by iterating through all the courses List all courses available to the logged in user by iterating through all the courses
""" """
...@@ -406,7 +408,7 @@ def _accessible_courses_list(request): ...@@ -406,7 +408,7 @@ def _accessible_courses_list(request):
return has_studio_read_access(request.user, course.id) return has_studio_read_access(request.user, course.id)
courses = filter(course_filter, modulestore().get_courses()) courses = six.moves.filter(course_filter, modulestore().get_courses())
in_process_course_actions = get_in_process_course_actions(request) in_process_course_actions = get_in_process_course_actions(request)
return courses, in_process_course_actions return courses, in_process_course_actions
...@@ -455,12 +457,12 @@ def _accessible_courses_list_from_groups(request): ...@@ -455,12 +457,12 @@ def _accessible_courses_list_from_groups(request):
return courses_list.values(), in_process_course_actions return courses_list.values(), in_process_course_actions
def _accessible_libraries_list(user): def _accessible_libraries_iter(user):
""" """
List all libraries available to the logged in user by iterating through all libraries List all libraries available to the logged in user by iterating through all libraries
""" """
# No need to worry about ErrorDescriptors - split's get_libraries() never returns them. # No need to worry about ErrorDescriptors - split's get_libraries() never returns them.
return [lib for lib in modulestore().get_libraries() if has_studio_read_access(user, lib.location.library_key)] return (lib for lib in modulestore().get_libraries() if has_studio_read_access(user, lib.location.library_key))
@login_required @login_required
...@@ -469,29 +471,29 @@ def course_listing(request): ...@@ -469,29 +471,29 @@ def course_listing(request):
""" """
List all courses available to the logged in user List all courses available to the logged in user
""" """
courses, in_process_course_actions = get_courses_accessible_to_user(request) courses_iter, in_process_course_actions = get_courses_accessible_to_user(request)
user = request.user user = request.user
libraries = _accessible_libraries_list(request.user) if LIBRARIES_ENABLED else [] libraries = _accessible_libraries_iter(request.user) if LIBRARIES_ENABLED else []
def format_in_process_course_view(uca): def format_in_process_course_view(uca):
""" """
Return a dict of the data which the view requires for each unsucceeded course Return a dict of the data which the view requires for each unsucceeded course
""" """
return { return {
'display_name': uca.display_name, u'display_name': uca.display_name,
'course_key': unicode(uca.course_key), u'course_key': unicode(uca.course_key),
'org': uca.course_key.org, u'org': uca.course_key.org,
'number': uca.course_key.course, u'number': uca.course_key.course,
'run': uca.course_key.run, u'run': uca.course_key.run,
'is_failed': True if uca.state == CourseRerunUIStateManager.State.FAILED else False, u'is_failed': True if uca.state == CourseRerunUIStateManager.State.FAILED else False,
'is_in_progress': True if uca.state == CourseRerunUIStateManager.State.IN_PROGRESS else False, u'is_in_progress': True if uca.state == CourseRerunUIStateManager.State.IN_PROGRESS else False,
'dismiss_link': reverse_course_url( u'dismiss_link': reverse_course_url(
'course_notifications_handler', u'course_notifications_handler',
uca.course_key, uca.course_key,
kwargs={ kwargs={
'action_state_id': uca.id, u'action_state_id': uca.id,
}, },
) if uca.state == CourseRerunUIStateManager.State.FAILED else '' ) if uca.state == CourseRerunUIStateManager.State.FAILED else u''
} }
def format_library_for_view(library): def format_library_for_view(library):
...@@ -499,29 +501,29 @@ def course_listing(request): ...@@ -499,29 +501,29 @@ def course_listing(request):
Return a dict of the data which the view requires for each library Return a dict of the data which the view requires for each library
""" """
return { return {
'display_name': library.display_name, u'display_name': library.display_name,
'library_key': unicode(library.location.library_key), u'library_key': unicode(library.location.library_key),
'url': reverse_library_url('library_handler', unicode(library.location.library_key)), u'url': reverse_library_url(u'library_handler', unicode(library.location.library_key)),
'org': library.display_org_with_default, u'org': library.display_org_with_default,
'number': library.display_number_with_default, u'number': library.display_number_with_default,
'can_edit': has_studio_write_access(request.user, library.location.library_key), u'can_edit': has_studio_write_access(request.user, library.location.library_key),
} }
courses = _remove_in_process_courses(courses, in_process_course_actions) courses_iter = _remove_in_process_courses(courses_iter, in_process_course_actions)
in_process_course_actions = [format_in_process_course_view(uca) for uca in in_process_course_actions] in_process_course_actions = [format_in_process_course_view(uca) for uca in in_process_course_actions]
return render_to_response('index.html', { return render_to_response(u'index.html', {
'courses': courses, u'courses': list(courses_iter),
'in_process_course_actions': in_process_course_actions, u'in_process_course_actions': in_process_course_actions,
'libraries_enabled': LIBRARIES_ENABLED, u'libraries_enabled': LIBRARIES_ENABLED,
'libraries': [format_library_for_view(lib) for lib in libraries], u'libraries': [format_library_for_view(lib) for lib in libraries],
'show_new_library_button': get_library_creator_status(user), u'show_new_library_button': get_library_creator_status(user),
'user': user, u'user': user,
'request_course_creator_url': reverse('contentstore.views.request_course_creator'), u'request_course_creator_url': reverse(u'contentstore.views.request_course_creator'),
'course_creator_status': _get_course_creator_status(user), u'course_creator_status': _get_course_creator_status(user),
'rerun_creator_status': GlobalStaff().has_user(user), u'rerun_creator_status': GlobalStaff().has_user(user),
'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False), u'allow_unicode_course_id': settings.FEATURES.get(u'ALLOW_UNICODE_COURSE_ID', False),
'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True), u'allow_course_reruns': settings.FEATURES.get(u'ALLOW_COURSE_RERUNS', True),
}) })
...@@ -623,18 +625,18 @@ def get_courses_accessible_to_user(request): ...@@ -623,18 +625,18 @@ def get_courses_accessible_to_user(request):
""" """
if GlobalStaff().has_user(request.user): if GlobalStaff().has_user(request.user):
# user has global access so no need to get courses from django groups # user has global access so no need to get courses from django groups
courses, in_process_course_actions = _accessible_courses_summary_list(request) courses, in_process_course_actions = _accessible_courses_summary_iter(request)
else: else:
try: try:
courses, in_process_course_actions = _accessible_courses_list_from_groups(request) courses, in_process_course_actions = _accessible_courses_list_from_groups(request)
except AccessListFallback: except AccessListFallback:
# user have some old groups or there was some error getting courses from django groups # user have some old groups or there was some error getting courses from django groups
# so fallback to iterating through all courses # so fallback to iterating through all courses
courses, in_process_course_actions = _accessible_courses_summary_list(request) courses, in_process_course_actions = _accessible_courses_summary_iter(request)
return courses, in_process_course_actions return courses, in_process_course_actions
def _remove_in_process_courses(courses, in_process_course_actions): def _remove_in_process_courses(courses_iter, in_process_course_actions):
""" """
removes any in-process courses in courses list. in-process actually refers to courses removes any in-process courses in courses list. in-process actually refers to courses
that are in the process of being generated for re-run that are in the process of being generated for re-run
...@@ -654,13 +656,12 @@ def _remove_in_process_courses(courses, in_process_course_actions): ...@@ -654,13 +656,12 @@ def _remove_in_process_courses(courses, in_process_course_actions):
'run': course.location.run 'run': course.location.run
} }
in_process_action_course_keys = [uca.course_key for uca in in_process_course_actions] in_process_action_course_keys = {uca.course_key for uca in in_process_course_actions}
courses = [ return (
format_course_for_view(course) format_course_for_view(course)
for course in courses for course in courses_iter
if not isinstance(course, ErrorDescriptor) and (course.id not in in_process_action_course_keys) if not isinstance(course, ErrorDescriptor) and (course.id not in in_process_action_course_keys)
] )
return courses
def course_outline_initial_state(locator_to_show, course_structure): def course_outline_initial_state(locator_to_show, course_structure):
...@@ -1014,10 +1015,10 @@ def settings_handler(request, course_key_string): ...@@ -1014,10 +1015,10 @@ def settings_handler(request, course_key_string):
if is_prerequisite_courses_enabled(): if is_prerequisite_courses_enabled():
courses, in_process_course_actions = get_courses_accessible_to_user(request) courses, in_process_course_actions = get_courses_accessible_to_user(request)
# exclude current course from the list of available courses # exclude current course from the list of available courses
courses = [course for course in courses if course.id != course_key] courses = (course for course in courses if course.id != course_key)
if courses: if courses:
courses = _remove_in_process_courses(courses, in_process_course_actions) courses = _remove_in_process_courses(courses, in_process_course_actions)
settings_context.update({'possible_pre_requisite_courses': courses}) settings_context.update({'possible_pre_requisite_courses': list(courses)})
if credit_eligibility_enabled: if credit_eligibility_enabled:
if is_credit_course(course_key): if is_credit_course(course_key):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment