Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
61d247d4
Commit
61d247d4
authored
May 24, 2017
by
J. Cliff Dyer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prefer iters and sets to lists
parent
3278fcf1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
78 additions
and
73 deletions
+78
-73
cms/djangoapps/contentstore/tests/test_course_listing.py
+28
-24
cms/djangoapps/contentstore/views/course.py
+50
-49
No files found.
cms/djangoapps/contentstore/tests/test_course_listing.py
View file @
61d247d4
...
...
@@ -17,11 +17,11 @@ from common.test.utils import XssTestMixin
from
xmodule.course_module
import
CourseSummary
from
contentstore.views.course
import
(
_accessible_courses_
list
,
_accessible_courses_
iter
,
_accessible_courses_list_from_groups
,
AccessListFallback
,
get_courses_accessible_to_user
,
_accessible_courses_summary_
list
,
_accessible_courses_summary_
iter
,
)
from
contentstore.utils
import
delete_course_and_groups
from
contentstore.tests.utils
import
AjaxEnabledTestClient
...
...
@@ -132,11 +132,12 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self
.
_create_course_with_access_groups
(
course_location
,
self
.
user
)
# 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
)
courses_summary_list
,
__
=
_accessible_courses_summary_
list
(
self
.
request
)
self
.
assertEqual
(
len
(
courses_summary_list
),
1
)
courses_summary_list
,
__
=
_accessible_courses_summary_
iter
(
self
.
request
)
self
.
assertEqual
(
len
(
list
(
courses_summary_list
)
),
1
)
# get courses by reversing group name formats
courses_list_by_groups
,
__
=
_accessible_courses_list_from_groups
(
self
.
request
)
...
...
@@ -179,8 +180,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# Verify that CCX courses are filtered out while iterating over all courses
mocked_ccx_course
=
Mock
(
id
=
ccx_course_key
)
with
patch
(
'xmodule.modulestore.mixed.MixedModuleStore.get_courses'
,
return_value
=
[
mocked_ccx_course
]):
courses_
list
,
__
=
_accessible_courses_list
(
self
.
request
)
self
.
assertEqual
(
len
(
courses_list
),
0
)
courses_
iter
,
__
=
_accessible_courses_iter
(
self
.
request
)
self
.
assertEqual
(
len
(
list
(
courses_iter
)
),
0
)
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
split
,
'xmodule.modulestore.split_mongo.split_mongo_kvs.SplitMongoKVS'
),
...
...
@@ -201,8 +202,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self
.
assertIsInstance
(
self
.
store
.
get_course
(
course_key
),
ErrorDescriptor
)
# get courses through iterating all courses
courses_
list
,
__
=
_accessible_courses_list
(
self
.
request
)
self
.
assertEqual
(
courses_list
,
[])
courses_
iter
,
__
=
_accessible_courses_iter
(
self
.
request
)
self
.
assertEqual
(
list
(
courses_iter
)
,
[])
# get courses by reversing group name formats
courses_list_by_groups
,
__
=
_accessible_courses_list_from_groups
(
self
.
request
)
...
...
@@ -231,14 +232,14 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# Fetch accessible courses list & verify their count
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
self
.
assertTrue
(
all
(
isinstance
(
course
,
CourseSummary
)
for
course
in
courses_list_by_staff
))
# Now count the db queries for staff
with
check_mongo_calls
(
mongo_calls
):
_accessible_courses_summary_list
(
self
.
request
)
list
(
_accessible_courses_summary_iter
(
self
.
request
)
)
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
split
,
'xmodule.modulestore.split_mongo.split_mongo_kvs.SplitMongoKVS'
),
...
...
@@ -261,7 +262,8 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self
.
assertIsInstance
(
self
.
store
.
get_course
(
course_key
),
ErrorDescriptor
)
# 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
,
[])
# get courses by reversing group name formats
...
...
@@ -279,10 +281,12 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
self
.
_create_course_with_access_groups
(
course_key
,
self
.
user
,
store
)
# 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
)
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
# is returned
...
...
@@ -302,17 +306,17 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
CourseInstructorRole
(
course_key
)
.
add_users
(
self
.
user
)
# 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
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
courses_list_by_groups
,
__
=
_accessible_courses_list_from_groups
(
self
.
request
)
# Test that course list returns no course
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
]
)
...
...
@@ -344,13 +348,13 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# time the get courses by iterating through all courses
with
Timer
()
as
iteration_over_courses_time_1
:
courses_
list
,
__
=
_accessible_courses_list
(
self
.
request
)
self
.
assertEqual
(
len
(
courses_list
),
USER_COURSES_COUNT
)
courses_
iter
,
__
=
_accessible_courses_iter
(
self
.
request
)
self
.
assertEqual
(
len
(
list
(
courses_iter
)
),
USER_COURSES_COUNT
)
# time again the get courses by iterating through all courses
with
Timer
()
as
iteration_over_courses_time_2
:
courses_
list
,
__
=
_accessible_courses_list
(
self
.
request
)
self
.
assertEqual
(
len
(
courses_list
),
USER_COURSES_COUNT
)
courses_
iter
,
__
=
_accessible_courses_iter
(
self
.
request
)
self
.
assertEqual
(
len
(
list
(
courses_iter
)
),
USER_COURSES_COUNT
)
# time the get courses by reversing django groups
with
Timer
()
as
iteration_over_groups_time_1
:
...
...
@@ -372,7 +376,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
_accessible_courses_list_from_groups
(
self
.
request
)
with
check_mongo_calls
(
courses_list_calls
):
_accessible_courses_list
(
self
.
request
)
list
(
_accessible_courses_iter
(
self
.
request
)
)
# Calls:
# 1) query old mongo
# 2) get_more on old mongo
...
...
@@ -424,7 +428,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
# Verify fetched accessible courses list is a list of CourseSummery instances and test expacted
# 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
))
def
test_course_listing_with_actions_in_progress
(
self
):
...
...
@@ -447,7 +451,7 @@ class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
)
# 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'
):
"""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
)
...
...
cms/djangoapps/contentstore/views/course.py
View file @
61d247d4
...
...
@@ -17,6 +17,7 @@ import django.utils
from
django.utils.translation
import
ugettext
as
_
from
django.views.decorators.http
import
require_http_methods
,
require_GET
from
django.views.decorators.csrf
import
ensure_csrf_cookie
import
six
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
...
...
@@ -357,13 +358,14 @@ def get_in_process_course_actions(request):
return
[
course
for
course
in
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
)
]
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
"""
...
...
@@ -378,12 +380,12 @@ def _accessible_courses_summary_list(request):
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
)
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
"""
...
...
@@ -406,7 +408,7 @@ def _accessible_courses_list(request):
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
)
return
courses
,
in_process_course_actions
...
...
@@ -455,12 +457,12 @@ def _accessible_courses_list_from_groups(request):
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
"""
# 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
...
...
@@ -469,29 +471,29 @@ def course_listing(request):
"""
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
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
):
"""
Return a dict of the data which the view requires for each unsucceeded course
"""
return
{
'display_name'
:
uca
.
display_name
,
'course_key'
:
unicode
(
uca
.
course_key
),
'org'
:
uca
.
course_key
.
org
,
'number'
:
uca
.
course_key
.
course
,
'run'
:
uca
.
course_key
.
run
,
'is_failed'
:
True
if
uca
.
state
==
CourseRerunUIStateManager
.
State
.
FAILED
else
False
,
'is_in_progress'
:
True
if
uca
.
state
==
CourseRerunUIStateManager
.
State
.
IN_PROGRESS
else
False
,
'dismiss_link'
:
reverse_course_url
(
'course_notifications_handler'
,
u
'display_name'
:
uca
.
display_name
,
u
'course_key'
:
unicode
(
uca
.
course_key
),
u
'org'
:
uca
.
course_key
.
org
,
u
'number'
:
uca
.
course_key
.
course
,
u
'run'
:
uca
.
course_key
.
run
,
u
'is_failed'
:
True
if
uca
.
state
==
CourseRerunUIStateManager
.
State
.
FAILED
else
False
,
u
'is_in_progress'
:
True
if
uca
.
state
==
CourseRerunUIStateManager
.
State
.
IN_PROGRESS
else
False
,
u
'dismiss_link'
:
reverse_course_url
(
u
'course_notifications_handler'
,
uca
.
course_key
,
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
):
...
...
@@ -499,29 +501,29 @@ def course_listing(request):
Return a dict of the data which the view requires for each library
"""
return
{
'display_name'
:
library
.
display_name
,
'library_key'
:
unicode
(
library
.
location
.
library_key
),
'url'
:
reverse_library_url
(
'library_handler'
,
unicode
(
library
.
location
.
library_key
)),
'org'
:
library
.
display_org_with_default
,
'number'
:
library
.
display_number_with_default
,
'can_edit'
:
has_studio_write_access
(
request
.
user
,
library
.
location
.
library_key
),
u
'display_name'
:
library
.
display_name
,
u
'library_key'
:
unicode
(
library
.
location
.
library_key
),
u'url'
:
reverse_library_url
(
u
'library_handler'
,
unicode
(
library
.
location
.
library_key
)),
u
'org'
:
library
.
display_org_with_default
,
u
'number'
:
library
.
display_number_with_default
,
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
]
return
render_to_response
(
'index.html'
,
{
'courses'
:
courses
,
'in_process_course_actions'
:
in_process_course_actions
,
'libraries_enabled'
:
LIBRARIES_ENABLED
,
'libraries'
:
[
format_library_for_view
(
lib
)
for
lib
in
libraries
],
'show_new_library_button'
:
get_library_creator_status
(
user
),
'user'
:
user
,
'request_course_creator_url'
:
reverse
(
'contentstore.views.request_course_creator'
),
'course_creator_status'
:
_get_course_creator_status
(
user
),
'rerun_creator_status'
:
GlobalStaff
()
.
has_user
(
user
),
'allow_unicode_course_id'
:
settings
.
FEATURES
.
get
(
'ALLOW_UNICODE_COURSE_ID'
,
False
),
'allow_course_reruns'
:
settings
.
FEATURES
.
get
(
'ALLOW_COURSE_RERUNS'
,
True
),
return
render_to_response
(
u
'index.html'
,
{
u'courses'
:
list
(
courses_iter
)
,
u
'in_process_course_actions'
:
in_process_course_actions
,
u
'libraries_enabled'
:
LIBRARIES_ENABLED
,
u
'libraries'
:
[
format_library_for_view
(
lib
)
for
lib
in
libraries
],
u
'show_new_library_button'
:
get_library_creator_status
(
user
),
u
'user'
:
user
,
u'request_course_creator_url'
:
reverse
(
u
'contentstore.views.request_course_creator'
),
u
'course_creator_status'
:
_get_course_creator_status
(
user
),
u
'rerun_creator_status'
:
GlobalStaff
()
.
has_user
(
user
),
u'allow_unicode_course_id'
:
settings
.
FEATURES
.
get
(
u
'ALLOW_UNICODE_COURSE_ID'
,
False
),
u'allow_course_reruns'
:
settings
.
FEATURES
.
get
(
u
'ALLOW_COURSE_RERUNS'
,
True
),
})
...
...
@@ -623,18 +625,18 @@ def get_courses_accessible_to_user(request):
"""
if
GlobalStaff
()
.
has_user
(
request
.
user
):
# 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
:
try
:
courses
,
in_process_course_actions
=
_accessible_courses_list_from_groups
(
request
)
except
AccessListFallback
:
# user have some old groups or there was some error getting courses from django groups
# 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
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
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):
'run'
:
course
.
location
.
run
}
in_process_action_course_keys
=
[
uca
.
course_key
for
uca
in
in_process_course_actions
]
courses
=
[
in_process_action_course_keys
=
{
uca
.
course_key
for
uca
in
in_process_course_actions
}
return
(
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
)
]
return
courses
)
def
course_outline_initial_state
(
locator_to_show
,
course_structure
):
...
...
@@ -1014,10 +1015,10 @@ def settings_handler(request, course_key_string):
if
is_prerequisite_courses_enabled
():
courses
,
in_process_course_actions
=
get_courses_accessible_to_user
(
request
)
# 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
:
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
is_credit_course
(
course_key
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment