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
f10bcc1e
Commit
f10bcc1e
authored
Aug 07, 2014
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix get_courses.
parent
abbfa95e
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
62 additions
and
38 deletions
+62
-38
common/lib/xmodule/xmodule/modulestore/mixed.py
+45
-17
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
+17
-21
No files found.
common/lib/xmodule/xmodule/modulestore/mixed.py
View file @
f10bcc1e
...
...
@@ -8,11 +8,11 @@ In this way, courses can be served up both - say - XMLModuleStore or MongoModule
import
logging
from
contextlib
import
contextmanager
import
itertools
import
functools
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locator
import
Locator
from
.
import
ModuleStoreWriteBase
from
.
import
ModuleStoreEnum
...
...
@@ -25,40 +25,63 @@ log = logging.getLogger(__name__)
def
strip_key
(
func
):
"""
A decorator for stripping version and branch information from return values that are, or contain, locations.
Additionally, the decorated function is called with an optional 'field_decorator' parameter that can be used
to strip any location(-containing) fields, which are not directly returned by the function.
The behavior can be controlled by passing 'remove_version' and 'remove_branch' booleans to the decorated
function's kwargs.
"""
@functools.wraps
(
func
)
def
inner
(
*
args
,
**
kwargs
):
"""
Supported kwargs:
remove_version - If True, calls 'version_agnostic' on all return values, including those in lists and dicts.
remove_branch - If True, calls 'for_branch(None)' on all return values, including those in lists and dicts.
Note: The 'field_decorator' parameter passed to the decorated function is a function that honors the
values of these kwargs.
"""
# remove version and branch, by default
rem_vers
=
kwargs
.
pop
(
'remove_version'
,
True
)
rem_branch
=
kwargs
.
pop
(
'remove_branch'
,
False
)
# helper function for stripping individual values
def
strip_key_func
(
val
):
"""
Strips the version and branch information according to the settings of rem_vers and rem_branch.
Recursively calls this function if the given value has a 'location' attribute.
"""
retval
=
val
if
isinstance
(
retval
,
Locator
):
if
rem_vers
:
retval
=
retval
.
version_agnostic
()
if
rem_branch
:
retval
=
retval
.
for_branch
(
None
)
if
rem_vers
and
hasattr
(
retval
,
'version_agnostic'
):
retval
=
retval
.
version_agnostic
()
if
rem_branch
and
hasattr
(
retval
,
'for_branch'
):
retval
=
retval
.
for_branch
(
None
)
if
hasattr
(
retval
,
'location'
):
retval
.
location
=
strip_key_func
(
retval
.
location
)
return
retval
# decorator for field values
def
strip_key_field_decorator
(
field_value
):
# function for stripping both, collection of, and individual, values
def
strip_key_collection
(
field_value
):
"""
Calls strip_key_func for each element in the given value.
"""
if
rem_vers
or
rem_branch
:
if
isinstance
(
field_value
,
list
):
field_value
=
[
strip_key_func
(
fv
)
for
fv
in
field_value
]
elif
isinstance
(
field_value
,
dict
):
for
key
,
val
in
field_value
.
iteritems
():
field_value
[
key
]
=
strip_key_func
(
val
)
elif
hasattr
(
field_value
,
'location'
):
field_value
.
location
=
strip_key_func
(
field_value
.
location
)
else
:
field_value
=
strip_key_func
(
field_value
)
return
field_value
# call the function
retval
=
func
(
field_decorator
=
strip_key_
field_decorator
,
*
args
,
**
kwargs
)
# call the
decorated
function
retval
=
func
(
field_decorator
=
strip_key_
collection
,
*
args
,
**
kwargs
)
#
return the "decorated"
value
return
strip_key_
field_decorator
(
retval
)
#
strip the return
value
return
strip_key_
collection
(
retval
)
return
inner
...
...
@@ -219,10 +242,15 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
'''
Returns a list containing the top level XModuleDescriptors of the courses in this modulestore.
'''
courses
=
[]
courses
=
{}
for
store
in
self
.
modulestores
:
courses
.
extend
(
store
.
get_courses
(
**
kwargs
))
return
courses
# filter out ones which were fetched from earlier stores but locations may not be ==
for
course
in
store
.
get_courses
(
**
kwargs
):
course_id
=
self
.
_clean_course_id_for_mapping
(
course
.
id
)
if
course_id
not
in
courses
:
# course is indeed unique. save it in result
courses
[
course_id
]
=
course
return
courses
.
values
()
def
make_course_key
(
self
,
org
,
course
,
run
):
"""
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
View file @
f10bcc1e
...
...
@@ -91,7 +91,7 @@ class TestMixedModuleStore(unittest.TestCase):
"""
AssertEqual replacement for CourseLocator
"""
if
loc1
.
version_agnostic
()
!=
loc2
.
version_agnostic
(
):
if
loc1
.
for_branch
(
None
)
!=
loc2
.
for_branch
(
None
):
self
.
fail
(
self
.
_formatMessage
(
msg
,
u"{} != {}"
.
format
(
unicode
(
loc1
),
unicode
(
loc2
))))
def
setUp
(
self
):
...
...
@@ -125,13 +125,13 @@ class TestMixedModuleStore(unittest.TestCase):
# create course
self
.
course
=
self
.
store
.
create_course
(
course_key
.
org
,
course_key
.
course
,
course_key
.
run
,
self
.
user_id
)
if
isinstance
(
self
.
course
.
id
,
CourseLocator
):
self
.
course_locations
[
self
.
MONGO_COURSEID
]
=
self
.
course
.
location
.
version_agnostic
()
self
.
course_locations
[
self
.
MONGO_COURSEID
]
=
self
.
course
.
location
else
:
self
.
assertEqual
(
self
.
course
.
id
,
course_key
)
# create chapter
chapter
=
self
.
store
.
create_child
(
self
.
user_id
,
self
.
course
.
location
,
'chapter'
,
block_id
=
'Overview'
)
self
.
writable_chapter_location
=
chapter
.
location
.
version_agnostic
()
self
.
writable_chapter_location
=
chapter
.
location
def
_create_block_hierarchy
(
self
):
"""
...
...
@@ -176,13 +176,13 @@ class TestMixedModuleStore(unittest.TestCase):
def
create_sub_tree
(
parent
,
block_info
):
block
=
self
.
store
.
create_child
(
self
.
user_id
,
parent
.
location
.
version_agnostic
()
,
self
.
user_id
,
parent
.
location
,
block_info
.
category
,
block_id
=
block_info
.
display_name
,
fields
=
{
'display_name'
:
block_info
.
display_name
},
)
for
tree
in
block_info
.
sub_tree
:
create_sub_tree
(
block
,
tree
)
setattr
(
self
,
block_info
.
field_name
,
block
.
location
.
version_agnostic
()
)
setattr
(
self
,
block_info
.
field_name
,
block
.
location
)
for
tree
in
trees
:
create_sub_tree
(
self
.
course
,
tree
)
...
...
@@ -386,7 +386,7 @@ class TestMixedModuleStore(unittest.TestCase):
# Create dummy direct only xblocks
chapter
=
self
.
store
.
create_item
(
self
.
user_id
,
test_course
.
id
.
version_agnostic
()
,
test_course
.
id
,
'chapter'
,
block_id
=
'vertical_container'
)
...
...
@@ -407,7 +407,7 @@ class TestMixedModuleStore(unittest.TestCase):
# Create a dummy component to test against
xblock
=
self
.
store
.
create_item
(
self
.
user_id
,
test_course
.
id
.
version_agnostic
()
,
test_course
.
id
,
'vertical'
,
block_id
=
'test_vertical'
)
...
...
@@ -522,7 +522,7 @@ class TestMixedModuleStore(unittest.TestCase):
revision
=
ModuleStoreEnum
.
RevisionOption
.
draft_preferred
)
self
.
store
.
publish
(
private_vert
.
location
.
version_agnostic
()
,
self
.
user_id
)
self
.
store
.
publish
(
private_vert
.
location
,
self
.
user_id
)
private_leaf
.
display_name
=
'change me'
private_leaf
=
self
.
store
.
update_item
(
private_leaf
,
self
.
user_id
)
mongo_store
=
self
.
store
.
_get_modulestore_for_courseid
(
self
.
_course_key_from_string
(
self
.
MONGO_COURSEID
))
...
...
@@ -538,11 +538,7 @@ class TestMixedModuleStore(unittest.TestCase):
mongo_store
=
self
.
store
.
_get_modulestore_for_courseid
(
self
.
_course_key_from_string
(
self
.
MONGO_COURSEID
))
with
check_mongo_calls
(
mongo_store
,
max_find
,
max_send
):
courses
=
self
.
store
.
get_courses
()
course_ids
=
[
course
.
location
.
version_agnostic
()
if
hasattr
(
course
.
location
,
'version_agnostic'
)
else
course
.
location
for
course
in
courses
]
course_ids
=
[
course
.
location
for
course
in
courses
]
self
.
assertEqual
(
len
(
courses
),
3
,
"Not 3 courses: {}"
.
format
(
course_ids
))
self
.
assertIn
(
self
.
course_locations
[
self
.
MONGO_COURSEID
],
course_ids
)
self
.
assertIn
(
self
.
course_locations
[
self
.
XML_COURSEID1
],
course_ids
)
...
...
@@ -622,7 +618,7 @@ class TestMixedModuleStore(unittest.TestCase):
self
.
_create_block_hierarchy
()
# publish the course
self
.
course
=
self
.
store
.
publish
(
self
.
course
.
location
.
version_agnostic
()
,
self
.
user_id
)
self
.
course
=
self
.
store
.
publish
(
self
.
course
.
location
,
self
.
user_id
)
# make drafts of verticals
self
.
store
.
convert_to_draft
(
self
.
vertical_x1a
,
self
.
user_id
)
...
...
@@ -648,7 +644,7 @@ class TestMixedModuleStore(unittest.TestCase):
])
# publish the course again
self
.
store
.
publish
(
self
.
course
.
location
.
version_agnostic
()
,
self
.
user_id
)
self
.
store
.
publish
(
self
.
course
.
location
,
self
.
user_id
)
self
.
verify_get_parent_locations_results
([
(
child_to_move_location
,
new_parent_location
,
None
),
(
child_to_move_location
,
new_parent_location
,
ModuleStoreEnum
.
RevisionOption
.
draft_preferred
),
...
...
@@ -888,7 +884,7 @@ class TestMixedModuleStore(unittest.TestCase):
self
.
initdb
(
default_ms
)
block
=
self
.
store
.
create_item
(
self
.
user_id
,
self
.
course
.
location
.
version_agnostic
()
.
course_key
,
self
.
course
.
location
.
course_key
,
'problem'
)
self
.
assertEqual
(
self
.
user_id
,
block
.
edited_by
)
...
...
@@ -899,7 +895,7 @@ class TestMixedModuleStore(unittest.TestCase):
self
.
initdb
(
default_ms
)
block
=
self
.
store
.
create_item
(
self
.
user_id
,
self
.
course
.
location
.
version_agnostic
()
.
course_key
,
self
.
course
.
location
.
course_key
,
'problem'
)
self
.
assertEqual
(
self
.
user_id
,
block
.
subtree_edited_by
)
...
...
@@ -944,7 +940,7 @@ class TestMixedModuleStore(unittest.TestCase):
self
.
_create_block_hierarchy
()
# publish
self
.
store
.
publish
(
self
.
course
.
location
.
version_agnostic
()
,
self
.
user_id
)
self
.
store
.
publish
(
self
.
course
.
location
,
self
.
user_id
)
published_xblock
=
self
.
store
.
get_item
(
self
.
vertical_x1a
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
...
...
@@ -980,7 +976,7 @@ class TestMixedModuleStore(unittest.TestCase):
# start off as Private
item
=
self
.
store
.
create_child
(
self
.
user_id
,
self
.
writable_chapter_location
,
'problem'
,
'test_compute_publish_state'
)
item_location
=
item
.
location
.
version_agnostic
()
item_location
=
item
.
location
mongo_store
=
self
.
store
.
_get_modulestore_for_courseid
(
self
.
_course_key_from_string
(
self
.
MONGO_COURSEID
))
with
check_mongo_calls
(
mongo_store
,
max_find
,
max_send
):
self
.
assertEquals
(
self
.
store
.
compute_publish_state
(
item
),
PublishState
.
private
)
...
...
@@ -1030,13 +1026,13 @@ class TestMixedModuleStore(unittest.TestCase):
test_course
=
self
.
store
.
create_course
(
'testx'
,
'GreekHero'
,
'test_run'
,
self
.
user_id
)
self
.
assertEqual
(
self
.
store
.
compute_publish_state
(
test_course
),
PublishState
.
public
)
test_course_key
=
test_course
.
id
.
version_agnostic
()
test_course_key
=
test_course
.
id
# test create_item of direct-only category to make sure we are autopublishing
chapter
=
self
.
store
.
create_item
(
self
.
user_id
,
test_course_key
,
'chapter'
,
'Overview'
)
self
.
assertEqual
(
self
.
store
.
compute_publish_state
(
chapter
),
PublishState
.
public
)
chapter_location
=
chapter
.
location
.
version_agnostic
()
chapter_location
=
chapter
.
location
# test create_child of direct-only category to make sure we are autopublishing
sequential
=
self
.
store
.
create_child
(
self
.
user_id
,
chapter_location
,
'sequential'
,
'Sequence'
)
...
...
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