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
37b528b3
Commit
37b528b3
authored
Oct 28, 2013
by
brianhw
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1387 from edx/fix/vik/peer-linking
Peer grading linking issue
parents
35d58b98
fd72005a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
136 additions
and
67 deletions
+136
-67
common/lib/xmodule/xmodule/peer_grading_module.py
+39
-27
common/lib/xmodule/xmodule/tests/test_peer_grading.py
+97
-40
No files found.
common/lib/xmodule/xmodule/peer_grading_module.py
View file @
37b528b3
...
...
@@ -104,30 +104,28 @@ class PeerGradingModule(PeerGradingFields, XModule):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
PeerGradingModule
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
#We need to set the location here so the child modules can use it
# Copy this to a new variable so that we can edit it if needed.
# We need to edit it if the linked module cannot be found, so
# we can revert to panel model.
self
.
use_for_single_location_local
=
self
.
use_for_single_location
# We need to set the location here so the child modules can use it.
self
.
runtime
.
set
(
'location'
,
self
.
location
)
if
(
self
.
runtime
.
open_ended_grading_interface
):
self
.
peer_gs
=
PeerGradingService
(
self
.
system
.
open_ended_grading_interface
,
self
.
system
)
else
:
self
.
peer_gs
=
MockPeerGradingService
()
if
self
.
use_for_single_location
:
try
:
linked_descriptors
=
self
.
descriptor
.
get_required_module_descriptors
()
if
len
(
linked_descriptors
)
==
0
:
error_msg
=
"Peer grading module {0} is trying to use single problem mode without "
"a location specified."
.
format
(
self
.
location
)
log
.
error
(
error_msg
)
raise
InvalidLinkLocation
(
error_msg
)
if
self
.
use_for_single_location_local
:
linked_descriptors
=
self
.
descriptor
.
get_required_module_descriptors
()
if
len
(
linked_descriptors
)
==
0
:
error_msg
=
"Peer grading module {0} is trying to use single problem mode without "
"a location specified."
.
format
(
self
.
location
)
log
.
error
(
error_msg
)
# Change module over to panel mode from single problem mode.
self
.
use_for_single_location_local
=
False
else
:
self
.
linked_problem
=
self
.
system
.
get_module
(
linked_descriptors
[
0
])
except
ItemNotFoundError
:
log
.
error
(
"Linked location {0} for peer grading module {1} does not exist"
.
format
(
self
.
link_to_location
,
self
.
location
))
raise
except
NoPathToItem
:
log
.
error
(
"Linked location {0} for peer grading module {1} cannot be linked to."
.
format
(
self
.
link_to_location
,
self
.
location
))
raise
try
:
self
.
timeinfo
=
TimeInfo
(
self
.
due
,
self
.
graceperiod
)
...
...
@@ -175,7 +173,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
"""
if
self
.
closed
():
return
self
.
peer_grading_closed
()
if
not
self
.
use_for_single_location
:
if
not
self
.
use_for_single_location
_local
:
return
self
.
peer_grading
()
else
:
return
self
.
peer_grading_problem
({
'location'
:
self
.
link_to_location
})[
'html'
]
...
...
@@ -236,7 +234,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
'score'
:
score
,
'total'
:
max_score
,
}
if
not
self
.
use_for_single_location
or
not
self
.
graded
:
if
not
self
.
use_for_single_location
_local
or
not
self
.
graded
:
return
score_dict
try
:
...
...
@@ -270,7 +268,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
randomization, and 5/7 on another
'''
max_grade
=
None
if
self
.
use_for_single_location
and
self
.
graded
:
if
self
.
use_for_single_location
_local
and
self
.
graded
:
max_grade
=
self
.
weight
return
max_grade
...
...
@@ -492,7 +490,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
Show the Peer grading closed template
'''
html
=
self
.
system
.
render_template
(
'peer_grading/peer_grading_closed.html'
,
{
'use_for_single_location'
:
self
.
use_for_single_location
'use_for_single_location'
:
self
.
use_for_single_location
_local
})
return
html
...
...
@@ -578,7 +576,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
'error_text'
:
error_text
,
# Checked above
'staff_access'
:
False
,
'use_single_location'
:
self
.
use_for_single_location
,
'use_single_location'
:
self
.
use_for_single_location
_local
,
})
return
html
...
...
@@ -588,7 +586,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
Show individual problem interface
'''
if
data
is
None
or
data
.
get
(
'location'
)
is
None
:
if
not
self
.
use_for_single_location
:
if
not
self
.
use_for_single_location
_local
:
# This is an error case, because it must be set to use a single location to be called without get parameters
# This is a dev_facing_error
log
.
error
(
...
...
@@ -610,7 +608,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
# Checked above
'staff_access'
:
False
,
'track_changes'
:
getattr
(
module
,
'track_changes'
,
False
),
'use_single_location'
:
self
.
use_for_single_location
,
'use_single_location'
:
self
.
use_for_single_location
_local
,
})
return
{
'html'
:
html
,
'success'
:
True
}
...
...
@@ -656,10 +654,24 @@ class PeerGradingDescriptor(PeerGradingFields, RawDescriptor):
return
non_editable_fields
def
get_required_module_descriptors
(
self
):
"""Returns a list of XModuleDescritpor instances upon which this module depends, but are
not children of this module"""
"""
Returns a list of XModuleDescriptor instances upon which this module depends, but are
not children of this module.
"""
# If use_for_single_location is True, this is linked to an open ended problem.
if
self
.
use_for_single_location
:
return
[
self
.
system
.
load_item
(
self
.
link_to_location
)]
# Try to load the linked module.
# If we can't load it, return empty list to avoid exceptions on progress page.
try
:
linked_module
=
self
.
system
.
load_item
(
self
.
link_to_location
)
return
[
linked_module
]
except
(
NoPathToItem
,
ItemNotFoundError
):
error_message
=
(
"Cannot find the combined open ended module "
"at location {0} being linked to from peer "
"grading module {1}"
)
.
format
(
self
.
link_to_location
,
self
.
location
)
log
.
error
(
error_message
)
return
[]
else
:
return
[]
...
...
common/lib/xmodule/xmodule/tests/test_peer_grading.py
View file @
37b528b3
import
unittest
from
xmodule.modulestore
import
Location
from
.
import
get_test_system
from
test_util_open_ended
import
MockQueryDict
,
DummyModulestore
from
xmodule.open_ended_grading_classes.peer_grading_service
import
MockPeerGradingService
import
json
import
logging
from
mock
import
Mock
from
xmodule.peer_grading_module
import
PeerGradingModule
,
InvalidLinkLocation
from
xblock.field_data
import
DictFieldData
from
xblock.fields
import
ScopeIds
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
,
NoPathToItem
import
json
import
logging
from
xmodule.modulestore
import
Location
from
xmodule.tests
import
get_test_system
,
get_test_descriptor_system
from
xmodule.tests.test_util_open_ended
import
MockQueryDict
,
DummyModulestore
from
xmodule.open_ended_grading_classes.peer_grading_service
import
MockPeerGradingService
from
xmodule.peer_grading_module
import
PeerGradingModule
,
PeerGradingDescriptor
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
,
NoPathToItem
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -37,7 +38,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
'feedback'
:
""
,
'rubric_scores[]'
:
[
0
,
1
],
'submission_flagged'
:
False
,
'answer_unknown'
:
False
,
'answer_unknown'
:
False
,
})
def
setUp
(
self
):
...
...
@@ -57,22 +58,22 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
@return:
"""
closed
=
self
.
peer_grading
.
closed
()
self
.
assert
Equal
(
closed
,
False
)
self
.
assert
False
(
closed
)
def
test_get_html
(
self
):
"""
Test to see if the module can be rendered
@return:
"""
html
=
self
.
peer_grading
.
get_html
()
_
html
=
self
.
peer_grading
.
get_html
()
def
test_get_data
(
self
):
"""
Try getting data from the external grading service
@return:
"""
success
,
data
=
self
.
peer_grading
.
query_data_for_location
(
self
.
problem_location
.
url
())
self
.
assert
Equal
(
success
,
True
)
success
,
_
data
=
self
.
peer_grading
.
query_data_for_location
(
self
.
problem_location
.
url
())
self
.
assert
True
(
success
)
def
test_get_score
(
self
):
"""
...
...
@@ -80,7 +81,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
@return:
"""
score
=
self
.
peer_grading
.
get_score
()
self
.
assert
Equals
(
score
[
'score'
],
None
)
self
.
assert
IsNone
(
score
[
'score'
]
)
def
test_get_max_score
(
self
):
"""
...
...
@@ -95,7 +96,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
Test to see if we can get the next mock submission
@return:
"""
success
,
next_submission
=
self
.
peer_grading
.
get_next_submission
({
'location'
:
'blah'
})
success
,
_
next_submission
=
self
.
peer_grading
.
get_next_submission
({
'location'
:
'blah'
})
self
.
assertEqual
(
success
,
True
)
def
test_save_grade
(
self
):
...
...
@@ -111,9 +112,8 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
Check to see if the student has calibrated yet
@return:
"""
calibrated_dict
=
{
'location'
:
"blah"
}
response
=
self
.
peer_grading
.
is_student_calibrated
(
self
.
calibrated_dict
)
self
.
assert
Equal
(
response
[
'success'
],
True
)
self
.
assert
True
(
response
[
'success'
]
)
def
test_show_calibration_essay
(
self
):
"""
...
...
@@ -121,7 +121,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
@return:
"""
response
=
self
.
peer_grading
.
show_calibration_essay
(
self
.
calibrated_dict
)
self
.
assert
Equal
(
response
[
'success'
],
True
)
self
.
assert
True
(
response
[
'success'
]
)
def
test_save_calibration_essay
(
self
):
"""
...
...
@@ -129,7 +129,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
@return:
"""
response
=
self
.
peer_grading
.
save_calibration_essay
(
self
.
save_dict
)
self
.
assert
Equal
(
response
[
'success'
],
True
)
self
.
assert
True
(
response
[
'success'
]
)
def
test_peer_grading_problem
(
self
):
"""
...
...
@@ -137,7 +137,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
@return:
"""
response
=
self
.
peer_grading
.
peer_grading_problem
(
self
.
coe_dict
)
self
.
assert
Equal
(
response
[
'success'
],
True
)
self
.
assert
True
(
response
[
'success'
]
)
def
test___find_corresponding_module_for_location_exceptions
(
self
):
"""
...
...
@@ -146,7 +146,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
@return:
"""
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
peer_grading
.
_find_corresponding_module_for_location
(
Location
(
'i4x'
,
'a'
,
'b'
,
'c'
,
'd'
))
self
.
peer_grading
.
_find_corresponding_module_for_location
(
Location
(
'i4x'
,
'a'
,
'b'
,
'c'
,
'd'
))
def
test_get_instance_state
(
self
):
"""
...
...
@@ -155,6 +155,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
"""
self
.
peer_grading
.
get_instance_state
()
class
MockPeerGradingServiceProblemList
(
MockPeerGradingService
):
def
get_problem_list
(
self
,
course_id
,
grader_id
):
return
{
'success'
:
True
,
...
...
@@ -162,13 +163,16 @@ class MockPeerGradingServiceProblemList(MockPeerGradingService):
{
"num_graded"
:
3
,
"num_pending"
:
681
,
"num_required"
:
3
,
"location"
:
"i4x://edX/open_ended/combinedopenended/SampleQuestion"
,
"problem_name"
:
"Peer-Graded Essay"
},
]}
class
PeerGradingModuleScoredTest
(
unittest
.
TestCase
,
DummyModulestore
):
"""
Test peer grading xmodule at the unit level. More detailed tests are difficult, as the module relies on an
external grading service.
"""
problem_location
=
Location
([
"i4x"
,
"edX"
,
"open_ended"
,
"peergrading"
,
"PeerGradingScored"
])
problem_location
=
Location
(
[
"i4x"
,
"edX"
,
"open_ended"
,
"peergrading"
,
"PeerGradingScored"
]
)
def
setUp
(
self
):
"""
Create a peer grading module from a test system
...
...
@@ -180,7 +184,7 @@ class PeerGradingModuleScoredTest(unittest.TestCase, DummyModulestore):
def
test_metadata_load
(
self
):
peer_grading
=
self
.
get_module_from_location
(
self
.
problem_location
,
COURSE
)
self
.
assert
Equal
(
peer_grading
.
closed
(),
False
)
self
.
assert
False
(
peer_grading
.
closed
()
)
def
test_problem_list
(
self
):
"""
...
...
@@ -217,6 +221,37 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
self
.
test_system
.
open_ended_grading_interface
=
None
self
.
setup_modulestore
(
COURSE
)
@property
def
field_data
(
self
):
"""
Setup the proper field data for a peer grading module.
"""
return
DictFieldData
({
'data'
:
'<peergrading/>'
,
'location'
:
self
.
problem_location
,
'use_for_single_location'
:
True
,
'link_to_location'
:
self
.
coe_location
.
url
(),
'graded'
:
True
,
})
@property
def
scope_ids
(
self
):
"""
Return the proper scope ids for the peer grading module.
"""
return
ScopeIds
(
None
,
None
,
self
.
problem_location
,
self
.
problem_location
)
def
_create_peer_grading_descriptor_with_linked_problem
(
self
):
# Initialize the peer grading module.
system
=
get_test_descriptor_system
()
return
system
.
construct_xblock_from_class
(
PeerGradingDescriptor
,
field_data
=
self
.
field_data
,
scope_ids
=
self
.
scope_ids
)
def
_create_peer_grading_with_linked_problem
(
self
,
location
,
valid_linked_descriptor
=
True
):
"""
Create a peer grading problem with a linked location.
...
...
@@ -235,34 +270,56 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
else
:
pg_descriptor
.
get_required_module_descriptors
=
lambda
:
[]
# Setup the proper field data for the peer grading module.
field_data
=
DictFieldData
({
'data'
:
'<peergrading/>'
,
'location'
:
self
.
problem_location
,
'use_for_single_location'
:
True
,
'link_to_location'
:
self
.
coe_location
.
url
(),
'graded'
:
True
,
})
# Initialize the peer grading module.
peer_grading
=
PeerGradingModule
(
pg_descriptor
,
self
.
test_system
,
field_data
,
ScopeIds
(
None
,
None
,
self
.
problem_location
,
self
.
problem_location
)
self
.
field_data
,
self
.
scope_ids
,
)
return
peer_grading
def
_get_descriptor_with_invalid_link
(
self
,
exception_to_raise
):
"""
Ensure that a peer grading descriptor with an invalid link will return an empty list.
"""
# Create a descriptor, and make loading an item throw an error.
descriptor
=
self
.
_create_peer_grading_descriptor_with_linked_problem
()
descriptor
.
system
.
load_item
=
Mock
(
side_effect
=
exception_to_raise
)
# Ensure that modules is a list of length 0.
modules
=
descriptor
.
get_required_module_descriptors
()
self
.
assertIsInstance
(
modules
,
list
)
self
.
assertEqual
(
len
(
modules
),
0
)
def
test_descriptor_with_nopath
(
self
):
"""
Test to see if a descriptor with a NoPathToItem error when trying to get
its linked module behaves properly.
"""
self
.
_get_descriptor_with_invalid_link
(
NoPathToItem
)
def
test_descriptor_with_item_not_found
(
self
):
"""
Test to see if a descriptor with an ItemNotFound error when trying to get
its linked module behaves properly.
"""
self
.
_get_descriptor_with_invalid_link
(
ItemNotFoundError
)
def
test_invalid_link
(
self
):
"""
Ensure that a peer grading problem with no linked locations
raises an error
.
Ensure that a peer grading problem with no linked locations
stays in panel mode
.
"""
# Setup the peer grading module with no linked locations.
with
self
.
assertRaises
(
InvalidLinkLocation
):
self
.
_create_peer_grading_with_linked_problem
(
self
.
coe_location
,
valid_linked_descriptor
=
False
)
peer_grading
=
self
.
_create_peer_grading_with_linked_problem
(
self
.
coe_location
,
valid_linked_descriptor
=
False
)
self
.
assertFalse
(
peer_grading
.
use_for_single_location_local
)
self
.
assertTrue
(
peer_grading
.
use_for_single_location
)
def
test_linked_problem
(
self
):
"""
...
...
@@ -284,7 +341,7 @@ class PeerGradingModuleLinkedTest(unittest.TestCase, DummyModulestore):
peer_grading
=
self
.
_create_peer_grading_with_linked_problem
(
self
.
coe_location
)
# If we specify a location, it will render the problem for that location.
data
=
peer_grading
.
handle_ajax
(
'problem'
,
{
'location'
:
self
.
coe_location
})
data
=
peer_grading
.
handle_ajax
(
'problem'
,
{
'location'
:
self
.
coe_location
})
self
.
assertTrue
(
json
.
loads
(
data
)[
'success'
])
# If we don't specify a location, it should use the linked location.
...
...
@@ -344,5 +401,5 @@ class PeerGradingModuleTrackChangesTest(unittest.TestCase, DummyModulestore):
"""
self
.
peer_grading
.
_find_corresponding_module_for_location
=
self
.
mock_track_changes_problem
response
=
self
.
peer_grading
.
peer_grading_problem
({
'location'
:
'mocked'
})
self
.
assert
Equal
(
response
[
'success'
],
True
)
self
.
assert
True
(
response
[
'success'
]
)
self
.
assertIn
(
"'track_changes': True"
,
response
[
'html'
])
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