Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xblock-drag-and-drop-v2
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
OpenEdx
xblock-drag-and-drop-v2
Commits
4c06585a
Commit
4c06585a
authored
Mar 21, 2017
by
Sanford Student
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
view should always show a weighted grade
parent
6a821d66
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
35 additions
and
22 deletions
+35
-22
drag_and_drop_v2/drag_and_drop_v2.py
+13
-6
tests/unit/test_advanced.py
+22
-16
No files found.
drag_and_drop_v2/drag_and_drop_v2.py
View file @
4c06585a
...
@@ -477,11 +477,10 @@ class DragAndDropBlock(
...
@@ -477,11 +477,10 @@ class DragAndDropBlock(
misplaced_items
.
append
(
self
.
_get_item_definition
(
int
(
item_id
)))
misplaced_items
.
append
(
self
.
_get_item_definition
(
int
(
item_id
)))
feedback_msgs
=
[
FeedbackMessage
(
item
[
'feedback'
][
'incorrect'
],
None
)
for
item
in
misplaced_items
]
feedback_msgs
=
[
FeedbackMessage
(
item
[
'feedback'
][
'incorrect'
],
None
)
for
item
in
misplaced_items
]
return
{
return
{
'correct'
:
correct
,
'correct'
:
correct
,
'attempts'
:
self
.
attempts
,
'attempts'
:
self
.
attempts
,
'grade'
:
self
.
_get_
raw
_earned_if_set
(),
'grade'
:
self
.
_get_
weighted
_earned_if_set
(),
'misplaced_items'
:
list
(
misplaced_ids
),
'misplaced_items'
:
list
(
misplaced_ids
),
'feedback'
:
self
.
_present_feedback
(
feedback_msgs
),
'feedback'
:
self
.
_present_feedback
(
feedback_msgs
),
'overall_feedback'
:
self
.
_present_feedback
(
overall_feedback_msgs
)
'overall_feedback'
:
self
.
_present_feedback
(
overall_feedback_msgs
)
...
@@ -679,10 +678,9 @@ class DragAndDropBlock(
...
@@ -679,10 +678,9 @@ class DragAndDropBlock(
item_feedback_key
=
'correct'
if
is_correct
else
'incorrect'
item_feedback_key
=
'correct'
if
is_correct
else
'incorrect'
item_feedback
=
FeedbackMessage
(
item
[
'feedback'
][
item_feedback_key
],
None
)
item_feedback
=
FeedbackMessage
(
item
[
'feedback'
][
item_feedback_key
],
None
)
overall_feedback
,
__
=
self
.
_get_feedback
()
overall_feedback
,
__
=
self
.
_get_feedback
()
return
{
return
{
'correct'
:
is_correct
,
'correct'
:
is_correct
,
'grade'
:
self
.
_get_
raw
_earned_if_set
(),
'grade'
:
self
.
_get_
weighted
_earned_if_set
(),
'finished'
:
self
.
_is_answer_correct
(),
'finished'
:
self
.
_is_answer_correct
(),
'overall_feedback'
:
self
.
_present_feedback
(
overall_feedback
),
'overall_feedback'
:
self
.
_present_feedback
(
overall_feedback
),
'feedback'
:
self
.
_present_feedback
([
item_feedback
])
'feedback'
:
self
.
_present_feedback
([
item_feedback
])
...
@@ -809,12 +807,11 @@ class DragAndDropBlock(
...
@@ -809,12 +807,11 @@ class DragAndDropBlock(
is_finished
=
self
.
_is_answer_correct
()
is_finished
=
self
.
_is_answer_correct
()
else
:
else
:
is_finished
=
not
self
.
attempts_remain
is_finished
=
not
self
.
attempts_remain
return
{
return
{
'items'
:
item_state
,
'items'
:
item_state
,
'finished'
:
is_finished
,
'finished'
:
is_finished
,
'attempts'
:
self
.
attempts
,
'attempts'
:
self
.
attempts
,
'grade'
:
self
.
_get_
raw
_earned_if_set
(),
'grade'
:
self
.
_get_
weighted
_earned_if_set
(),
'overall_feedback'
:
self
.
_present_feedback
(
overall_feedback_msgs
)
'overall_feedback'
:
self
.
_present_feedback
(
overall_feedback_msgs
)
}
}
...
@@ -946,6 +943,16 @@ class DragAndDropBlock(
...
@@ -946,6 +943,16 @@ class DragAndDropBlock(
else
:
else
:
return
None
return
None
def
_get_weighted_earned_if_set
(
self
):
"""
Returns student's grade with the problem weight applied if set, otherwise
None.
"""
if
self
.
fields
[
'raw_earned'
]
.
is_set_on
(
self
):
return
self
.
weighted_grade
()
else
:
return
None
def
_answer_correctness
(
self
):
def
_answer_correctness
(
self
):
"""
"""
Checks answer correctness:
Checks answer correctness:
...
...
tests/unit/test_advanced.py
View file @
4c06585a
...
@@ -91,14 +91,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -91,14 +91,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
self
.
assertEqual
(
res
[
self
.
OVERALL_FEEDBACK_KEY
],
expected_overall_feedback
)
self
.
assertEqual
(
res
[
self
.
OVERALL_FEEDBACK_KEY
],
expected_overall_feedback
)
def
test_drop_item_wrong_with_feedback
(
self
):
def
test_drop_item_wrong_with_feedback
(
self
):
self
.
block
.
weight
=
2
item_id
,
zone_id
=
0
,
self
.
ZONE_2
item_id
,
zone_id
=
0
,
self
.
ZONE_2
data
=
{
"val"
:
item_id
,
"zone"
:
zone_id
}
data
=
{
"val"
:
item_id
,
"zone"
:
zone_id
}
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
item_feedback_message
=
self
.
_make_item_feedback_message
(
item_id
)
item_feedback_message
=
self
.
_make_item_feedback_message
(
item_id
)
expected_feedback
=
[
item_feedback_message
]
if
item_feedback_message
else
[]
expected_feedback
=
[
item_feedback_message
]
if
item_feedback_message
else
[]
# the item was dropped into wrong zone, but we have two items that were correctly left in the bank,
# the item was dropped into wrong zone, but we have two items that were correctly left in the bank,
# so the score is 2 / 4.0.
# so the
raw
score is 2 / 4.0.
expected_grade
=
2
/
4.0
expected_grade
=
self
.
block
.
weight
*
2
/
4.0
self
.
assertEqual
(
res
,
{
self
.
assertEqual
(
res
,
{
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
INITIAL_FEEDBACK
)],
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
INITIAL_FEEDBACK
)],
...
@@ -109,14 +110,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -109,14 +110,15 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
})
})
def
test_drop_item_wrong_without_feedback
(
self
):
def
test_drop_item_wrong_without_feedback
(
self
):
self
.
block
.
weight
=
2
item_id
,
zone_id
=
2
,
self
.
ZONE_1
item_id
,
zone_id
=
2
,
self
.
ZONE_1
data
=
{
"val"
:
item_id
,
"zone"
:
zone_id
}
data
=
{
"val"
:
item_id
,
"zone"
:
zone_id
}
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
item_feedback_message
=
self
.
_make_item_feedback_message
(
item_id
)
item_feedback_message
=
self
.
_make_item_feedback_message
(
item_id
)
expected_feedback
=
[
item_feedback_message
]
if
item_feedback_message
else
[]
expected_feedback
=
[
item_feedback_message
]
if
item_feedback_message
else
[]
# the item was dropped into wrong zone, but we have two items that were correctly left in the bank,
# the item was dropped into wrong zone, but we have two items that were correctly left in the bank,
# so the score is 2 / 4.0.
# so the
raw
score is 2 / 4.0.
expected_grade
=
2
/
4.0
expected_grade
=
self
.
block
.
weight
*
2
/
4.0
self
.
assertEqual
(
res
,
{
self
.
assertEqual
(
res
,
{
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
INITIAL_FEEDBACK
)],
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
INITIAL_FEEDBACK
)],
...
@@ -127,14 +129,16 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -127,14 +129,16 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
})
})
def
test_drop_item_correct
(
self
):
def
test_drop_item_correct
(
self
):
self
.
block
.
weight
=
2
item_id
,
zone_id
=
0
,
self
.
ZONE_1
item_id
,
zone_id
=
0
,
self
.
ZONE_1
data
=
{
"val"
:
item_id
,
"zone"
:
zone_id
}
data
=
{
"val"
:
item_id
,
"zone"
:
zone_id
}
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
item_feedback_message
=
self
.
_make_item_feedback_message
(
item_id
,
key
=
"correct"
)
item_feedback_message
=
self
.
_make_item_feedback_message
(
item_id
,
key
=
"correct"
)
expected_feedback
=
[
item_feedback_message
]
if
item_feedback_message
else
[]
expected_feedback
=
[
item_feedback_message
]
if
item_feedback_message
else
[]
# Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank.
# Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank.
# The only item that is not in correct position yet is item 1. The grade is therefore 3/4.
# The only item that is not in correct position yet is item 1. The grade is therefore 3/4. The weight of the
expected_grade
=
3
/
4.0
# problem means that the displayed grade will be 1.5.
expected_grade
=
self
.
block
.
weight
*
3
/
4.0
self
.
assertEqual
(
res
,
{
self
.
assertEqual
(
res
,
{
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
INITIAL_FEEDBACK
)],
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
INITIAL_FEEDBACK
)],
...
@@ -230,12 +234,13 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -230,12 +234,13 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
self
.
assertEqual
({
'value'
:
1
,
'max_value'
:
1
,
'only_if_higher'
:
None
},
published_grades
[
-
1
])
self
.
assertEqual
({
'value'
:
1
,
'max_value'
:
1
,
'only_if_higher'
:
None
},
published_grades
[
-
1
])
def
test_drop_item_final
(
self
):
def
test_drop_item_final
(
self
):
self
.
block
.
weight
=
2
data
=
{
"val"
:
0
,
"zone"
:
self
.
ZONE_1
}
data
=
{
"val"
:
0
,
"zone"
:
self
.
ZONE_1
}
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
data
)
# Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank.
# Item 0 is in correct zone, items 2 and 3 don't belong to any zone so it is correct to leave them in the bank.
# The only item that is not in correct position yet is item 1. The grade is therefore 3/4.
# The only item that is not in correct position yet is item 1. The
raw
grade is therefore 3/4.
expected_grade
=
3
/
4.0
expected_grade
=
self
.
block
.
weight
*
3
/
4.0
expected_state
=
{
expected_state
=
{
"items"
:
{
"items"
:
{
"0"
:
{
"correct"
:
True
,
"zone"
:
self
.
ZONE_1
}
"0"
:
{
"correct"
:
True
,
"zone"
:
self
.
ZONE_1
}
...
@@ -248,8 +253,8 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -248,8 +253,8 @@ class StandardModeFixture(BaseDragAndDropAjaxFixture):
self
.
assertEqual
(
expected_state
,
self
.
call_handler
(
'get_user_state'
,
method
=
"GET"
))
self
.
assertEqual
(
expected_state
,
self
.
call_handler
(
'get_user_state'
,
method
=
"GET"
))
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
{
"val"
:
1
,
"zone"
:
self
.
ZONE_2
})
res
=
self
.
call_handler
(
self
.
DROP_ITEM_HANDLER
,
{
"val"
:
1
,
"zone"
:
self
.
ZONE_2
})
# All four items are in correct position, so the final grade is 4/4.
# All four items are in correct position, so the final
raw
grade is 4/4.
expected_grade
=
4
/
4.0
expected_grade
=
self
.
block
.
weight
*
4
/
4.0
self
.
assertEqual
(
res
,
{
self
.
assertEqual
(
res
,
{
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
FINAL_FEEDBACK
)],
"overall_feedback"
:
[
self
.
_make_feedback_message
(
message
=
self
.
FINAL_FEEDBACK
)],
"finished"
:
True
,
"finished"
:
True
,
...
@@ -406,7 +411,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -406,7 +411,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
'only_if_higher'
:
None
,
'only_if_higher'
:
None
,
})
})
self
.
assertTrue
(
res
[
'correct'
])
self
.
assertTrue
(
res
[
'correct'
])
self
.
assertEqual
(
res
[
'grade'
],
1
)
self
.
assertEqual
(
res
[
'grade'
],
self
.
block
.
weight
)
@ddt.data
(
*
[
random
.
randint
(
1
,
50
)
for
_
in
xrange
(
5
)])
# pylint: disable=star-args
@ddt.data
(
*
[
random
.
randint
(
1
,
50
)
for
_
in
xrange
(
5
)])
# pylint: disable=star-args
def
test_do_attempt_incorrect_publish_grade
(
self
,
weight
):
def
test_do_attempt_incorrect_publish_grade
(
self
,
weight
):
...
@@ -424,7 +429,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -424,7 +429,7 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
'only_if_higher'
:
None
,
'only_if_higher'
:
None
,
})
})
self
.
assertFalse
(
res
[
'correct'
])
self
.
assertFalse
(
res
[
'correct'
])
self
.
assertEqual
(
res
[
'grade'
],
correctness
)
self
.
assertEqual
(
res
[
'grade'
],
correctness
*
self
.
block
.
weight
)
@ddt.data
(
*
[
random
.
randint
(
1
,
50
)
for
_
in
xrange
(
5
)])
# pylint: disable=star-args
@ddt.data
(
*
[
random
.
randint
(
1
,
50
)
for
_
in
xrange
(
5
)])
# pylint: disable=star-args
def
test_do_attempt_post_correct_no_publish_grade
(
self
,
weight
):
def
test_do_attempt_post_correct_no_publish_grade
(
self
,
weight
):
...
@@ -457,24 +462,25 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
...
@@ -457,24 +462,25 @@ class AssessmentModeFixture(BaseDragAndDropAjaxFixture):
self
.
_set_final_attempt
()
self
.
_set_final_attempt
()
expected_grade
=
self
.
_submit_partial_solution
()
expected_raw_grade
=
self
.
_submit_partial_solution
()
expected_weighted_grade
=
expected_raw_grade
*
self
.
block
.
weight
with
mock
.
patch
(
'workbench.runtime.WorkbenchRuntime.publish'
,
mock
.
Mock
())
as
patched_publish
:
with
mock
.
patch
(
'workbench.runtime.WorkbenchRuntime.publish'
,
mock
.
Mock
())
as
patched_publish
:
res
=
self
.
call_handler
(
self
.
DO_ATTEMPT_HANDLER
,
data
=
{})
res
=
self
.
call_handler
(
self
.
DO_ATTEMPT_HANDLER
,
data
=
{})
self
.
assertTrue
(
self
.
block
.
completed
)
self
.
assertTrue
(
self
.
block
.
completed
)
patched_publish
.
assert_called_once_with
(
self
.
block
,
'grade'
,
{
patched_publish
.
assert_called_once_with
(
self
.
block
,
'grade'
,
{
'value'
:
expected_grade
,
'value'
:
expected_
raw_
grade
,
'max_value'
:
1
,
'max_value'
:
1
,
'only_if_higher'
:
None
,
'only_if_higher'
:
None
,
})
})
expected_grade_feedback
=
self
.
_make_feedback_message
(
expected_grade_feedback
=
self
.
_make_feedback_message
(
FeedbackMessages
.
FINAL_ATTEMPT_TPL
.
format
(
score
=
expected_
grade
*
self
.
block
.
weight
),
FeedbackMessages
.
FINAL_ATTEMPT_TPL
.
format
(
score
=
expected_
weighted_grade
),
FeedbackMessages
.
MessageClasses
.
PARTIAL_SOLUTION
FeedbackMessages
.
MessageClasses
.
PARTIAL_SOLUTION
)
)
self
.
assertIn
(
expected_grade_feedback
,
res
[
self
.
OVERALL_FEEDBACK_KEY
])
self
.
assertIn
(
expected_grade_feedback
,
res
[
self
.
OVERALL_FEEDBACK_KEY
])
self
.
assertEqual
(
res
[
'grade'
],
expected_grade
)
self
.
assertEqual
(
res
[
'grade'
],
expected_
weighted_
grade
)
@ddt.data
(
*
[
random
.
randint
(
1
,
50
)
for
_
in
xrange
(
5
)])
# pylint: disable=star-args
@ddt.data
(
*
[
random
.
randint
(
1
,
50
)
for
_
in
xrange
(
5
)])
# pylint: disable=star-args
def
test_do_attempt_incorrect_final_attempt_after_correct
(
self
,
weight
):
def
test_do_attempt_incorrect_final_attempt_after_correct
(
self
,
weight
):
...
...
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