Commit 06a20054 by Adam

Merge pull request #9561 from edx/hotfix/2015-09-01a

Revert "OSPR-535 Partial Credit"
parents 02cc9ca8 f8266235
......@@ -10,7 +10,7 @@ class CorrectMap(object):
in a capa problem. The response evaluation result for each answer_id includes
(correctness, npoints, msg, hint, hintmode).
- correctness : 'correct', 'incorrect', or 'partially-correct'
- correctness : either 'correct' or 'incorrect'
- npoints : None, or integer specifying number of points awarded for this answer_id
- msg : string (may have HTML) giving extra message response
(displayed below textline or textbox)
......@@ -101,23 +101,10 @@ class CorrectMap(object):
self.set(k, **correct_map[k])
def is_correct(self, answer_id):
"""
Takes an answer_id
Returns true if the problem is correct OR partially correct.
"""
if answer_id in self.cmap:
return self.cmap[answer_id]['correctness'] in ['correct', 'partially-correct']
return None
def is_partially_correct(self, answer_id):
"""
Takes an answer_id
Returns true if the problem is partially correct.
"""
if answer_id in self.cmap:
return self.cmap[answer_id]['correctness'] == 'partially-correct'
return None
def is_queued(self, answer_id):
return answer_id in self.cmap and self.cmap[answer_id]['queuestate'] is not None
......
......@@ -85,7 +85,6 @@ class Status(object):
names = {
'correct': _('correct'),
'incorrect': _('incorrect'),
'partially-correct': _('partially correct'),
'incomplete': _('incomplete'),
'unanswered': _('unanswered'),
'unsubmitted': _('unanswered'),
......@@ -95,7 +94,6 @@ class Status(object):
# Translators: these are tooltips that indicate the state of an assessment question
'correct': _('This is correct.'),
'incorrect': _('This is incorrect.'),
'partially-correct': _('This is partially correct.'),
'unanswered': _('This is unanswered.'),
'unsubmitted': _('This is unanswered.'),
'queued': _('This is being processed.'),
......@@ -898,7 +896,7 @@ class MatlabInput(CodeInput):
Right now, we only want this button to show up when a problem has not been
checked.
"""
if self.status in ['correct', 'incorrect', 'partially-correct']:
if self.status in ['correct', 'incorrect']:
return False
else:
return True
......
......@@ -17,7 +17,7 @@
<div id="input_${id}_preview" class="equation"></div>
<p id="answer_${id}" class="answer"></p>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</div>
......@@ -7,8 +7,6 @@
<%
if status == 'correct':
correctness = 'correct'
elif status == 'partially-correct':
correctness = 'partially-correct'
elif status == 'incorrect':
correctness = 'incorrect'
else:
......@@ -33,7 +31,7 @@
/> ${choice_description}
% if input_type == 'radio' and ( (isinstance(value, basestring) and (choice_id == value)) or (not isinstance(value, basestring) and choice_id in value) ):
% if status in ('correct', 'partially-correct', 'incorrect') and not show_correctness=='never':
% if status in ('correct', 'incorrect') and not show_correctness=='never':
<span class="sr status">${choice_description|h} - ${status.display_name}</span>
% endif
% endif
......@@ -62,4 +60,4 @@
% if msg:
<span class="message">${msg|n}</span>
% endif
</form>
\ No newline at end of file
</form>
......@@ -20,8 +20,6 @@
correctness = 'correct'
elif status == 'incorrect':
correctness = 'incorrect'
elif status == 'partially-correct':
correctness = 'partially-correct'
else:
correctness = None
%>
......
......@@ -9,7 +9,7 @@
<div class="script_placeholder" data-src="/static/js/sylvester.js"></div>
<div class="script_placeholder" data-src="/static/js/crystallography.js"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="status ${status.classname}" id="status_${id}">
% endif
......@@ -25,7 +25,7 @@
<span class="message">${msg|n}</span>
% endif
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</section>
......@@ -2,7 +2,7 @@
<div class="script_placeholder" data-src="/static/js/capa/protex/protex.nocache.js?raw"/>
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -15,7 +15,7 @@
</p>
<p id="answer_${id}" class="answer"></p>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</section>
......@@ -8,7 +8,7 @@
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/drag_and_drop.js"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -26,7 +26,7 @@
<span class="message">${msg|n}</span>
% endif
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</div>
......@@ -2,7 +2,7 @@
<div class="script_placeholder" data-src="/static/js/capa/genex/genex.nocache.js?raw"/>
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -16,7 +16,7 @@
</p>
<p id="answer_${id}" class="answer"></p>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</section>
......
<section id="editamoleculeinput_${id}" class="editamoleculeinput">
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -23,7 +23,7 @@
<div class="error_message" style="padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</section>
......@@ -20,7 +20,7 @@
<div class="script_placeholder" data-src="${jschannel_loader}"/>
<div class="script_placeholder" data-src="${jsinput_loader}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -47,7 +47,7 @@
<div class="error_message" style="padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
......
......@@ -7,7 +7,7 @@
<div class="script_placeholder" data-src="${preprocessor['script_src']}"/>
% endif
% if status in ('unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete'):
% if status in ('unsubmitted', 'correct', 'incorrect', 'incomplete'):
<div class="${status.classname} ${doinline}" id="status_${id}">
% endif
% if hidden:
......@@ -50,7 +50,7 @@
% endif
% if status in ('unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete'):
% if status in ('unsubmitted', 'correct', 'incorrect', 'incomplete'):
</div>
% endif
......
......@@ -11,7 +11,7 @@
<div class="script_placeholder" data-src="/static/js/vsepr/vsepr.js"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -28,7 +28,7 @@
% if msg:
<span class="message">${msg|n}</span>
% endif
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
</section>
......@@ -49,9 +49,6 @@ class ResponseXMLFactory(object):
*num_inputs*: The number of input elements
to create [DEFAULT: 1]
*credit_type*: String of comma-separated words specifying the
partial credit grading scheme.
Returns a string representation of the XML tree.
"""
......@@ -61,7 +58,6 @@ class ResponseXMLFactory(object):
script = kwargs.get('script', None)
num_responses = kwargs.get('num_responses', 1)
num_inputs = kwargs.get('num_inputs', 1)
credit_type = kwargs.get('credit_type', None)
# The root is <problem>
root = etree.Element("problem")
......@@ -79,11 +75,6 @@ class ResponseXMLFactory(object):
# Add the response(s)
for __ in range(int(num_responses)):
response_element = self.create_response_element(**kwargs)
# Set partial credit
if credit_type is not None:
response_element.set('partial_credit', str(credit_type))
root.append(response_element)
# Add input elements
......@@ -141,10 +132,6 @@ class ResponseXMLFactory(object):
*choice_names": List of strings identifying the choices.
If specified, you must ensure that
len(choice_names) == len(choices)
*points*: List of strings giving partial credit values (0-1)
for each choice. Interpreted as floats in problem.
If specified, ensure len(points) == len(choices)
"""
# Names of group elements
group_element_names = {
......@@ -157,23 +144,15 @@ class ResponseXMLFactory(object):
choices = kwargs.get('choices', [True])
choice_type = kwargs.get('choice_type', 'multiple')
choice_names = kwargs.get('choice_names', [None] * len(choices))
points = kwargs.get('points', [None] * len(choices))
# Create the <choicegroup>, <checkboxgroup>, or <radiogroup> element
assert choice_type in group_element_names
group_element = etree.Element(group_element_names[choice_type])
# Create the <choice> elements
for (correct_val, name, pointval) in zip(choices, choice_names, points):
for (correct_val, name) in zip(choices, choice_names):
choice_element = etree.SubElement(group_element, "choice")
if correct_val is True:
correctness = 'true'
elif correct_val is False:
correctness = 'false'
elif 'partial' in correct_val:
correctness = 'partial'
choice_element.set('correct', correctness)
choice_element.set("correct", "true" if correct_val else "false")
# Add a name identifying the choice, if one exists
# For simplicity, we use the same string as both the
......@@ -182,10 +161,6 @@ class ResponseXMLFactory(object):
choice_element.text = str(name)
choice_element.set("name", str(name))
# Add point values for partially-correct choices.
if pointval:
choice_element.set("point_value", str(pointval))
return group_element
......@@ -201,22 +176,10 @@ class NumericalResponseXMLFactory(ResponseXMLFactory):
*tolerance*: The tolerance within which a response
is considered correct. Can be a decimal (e.g. "0.01")
or percentage (e.g. "2%")
*credit_type*: String of comma-separated words specifying the
partial credit grading scheme.
*partial_range*: The multiplier for the tolerance that will
still provide partial credit in the "close" grading style
*partial_answers*: A string of comma-separated alternate
answers that will receive partial credit in the "list" style
"""
answer = kwargs.get('answer', None)
tolerance = kwargs.get('tolerance', None)
credit_type = kwargs.get('credit_type', None)
partial_range = kwargs.get('partial_range', None)
partial_answers = kwargs.get('partial_answers', None)
response_element = etree.Element('numericalresponse')
......@@ -230,13 +193,6 @@ class NumericalResponseXMLFactory(ResponseXMLFactory):
responseparam_element = etree.SubElement(response_element, 'responseparam')
responseparam_element.set('type', 'tolerance')
responseparam_element.set('default', str(tolerance))
if partial_range is not None and 'close' in credit_type:
responseparam_element.set('partial_range', str(partial_range))
if partial_answers is not None and 'list' in credit_type:
# The line below throws a false positive pylint violation, so it's excepted.
responseparam_element = etree.SubElement(response_element, 'responseparam') # pylint: disable=E1101
responseparam_element.set('partial_answers', partial_answers)
return response_element
......@@ -673,25 +629,15 @@ class OptionResponseXMLFactory(ResponseXMLFactory):
*options*: a list of possible options the user can choose from [REQUIRED]
You must specify at least 2 options.
*correct_option*: a string with comma-separated correct choices [REQUIRED]
*partial_option*: a string with comma-separated partially-correct choices
*point_values*: a string with comma-separated values (0-1) that give the
partial credit values in the "points" grading scheme.
Must have one per partial option.
*credit_type*: String of comma-separated words specifying the
partial credit grading scheme.
*correct_option*: the correct choice from the list of options [REQUIRED]
"""
options_list = kwargs.get('options', None)
correct_option = kwargs.get('correct_option', None)
partial_option = kwargs.get('partial_option', None)
point_values = kwargs.get('point_values', None)
credit_type = kwargs.get('credit_type', None)
assert options_list and correct_option
assert len(options_list) > 1
for option in correct_option.split(','):
assert option.strip() in options_list
assert correct_option in options_list
# Create the <optioninput> element
optioninput_element = etree.Element("optioninput")
......@@ -705,15 +651,6 @@ class OptionResponseXMLFactory(ResponseXMLFactory):
# Set the "correct" attribute
optioninput_element.set('correct', str(correct_option))
# If we have 'points'-style partial credit...
if 'points' in str(credit_type):
# Set the "partial" attribute
optioninput_element.set('partial', str(partial_option))
# Set the "point_values" attribute, if it's specified.
if point_values is not None:
optioninput_element.set('point_values', str(point_values))
return optioninput_element
......
......@@ -17,7 +17,7 @@ class CorrectMapTest(unittest.TestCase):
self.cmap = CorrectMap()
def test_set_input_properties(self):
# Set the correctmap properties for three inputs
# Set the correctmap properties for two inputs
self.cmap.set(
answer_id='1_2_1',
correctness='correct',
......@@ -41,34 +41,15 @@ class CorrectMapTest(unittest.TestCase):
queuestate=None
)
self.cmap.set(
answer_id='3_2_1',
correctness='partially-correct',
npoints=3,
msg=None,
hint=None,
hintmode=None,
queuestate=None
)
# Assert that each input has the expected properties
self.assertTrue(self.cmap.is_correct('1_2_1'))
self.assertFalse(self.cmap.is_correct('2_2_1'))
self.assertTrue(self.cmap.is_correct('3_2_1'))
self.assertTrue(self.cmap.is_partially_correct('3_2_1'))
self.assertFalse(self.cmap.is_partially_correct('2_2_1'))
# Intentionally testing an item that's not in cmap.
self.assertFalse(self.cmap.is_partially_correct('9_2_1'))
self.assertEqual(self.cmap.get_correctness('1_2_1'), 'correct')
self.assertEqual(self.cmap.get_correctness('2_2_1'), 'incorrect')
self.assertEqual(self.cmap.get_correctness('3_2_1'), 'partially-correct')
self.assertEqual(self.cmap.get_npoints('1_2_1'), 5)
self.assertEqual(self.cmap.get_npoints('2_2_1'), 0)
self.assertEqual(self.cmap.get_npoints('3_2_1'), 3)
self.assertEqual(self.cmap.get_msg('1_2_1'), 'Test message')
self.assertEqual(self.cmap.get_msg('2_2_1'), None)
......@@ -102,8 +83,6 @@ class CorrectMapTest(unittest.TestCase):
# 3) incorrect, 5 points
# 4) incorrect, None points
# 5) correct, 0 points
# 4) partially correct, 2.5 points
# 5) partially correct, None points
self.cmap.set(
answer_id='1_2_1',
correctness='correct',
......@@ -134,30 +113,15 @@ class CorrectMapTest(unittest.TestCase):
npoints=0
)
self.cmap.set(
answer_id='6_2_1',
correctness='partially-correct',
npoints=2.5
)
self.cmap.set(
answer_id='7_2_1',
correctness='partially-correct',
npoints=None
)
# Assert that we get the expected points
# If points assigned --> npoints
# If no points assigned and correct --> 1 point
# If no points assigned and partially correct --> 1 point
# If no points assigned and incorrect --> 0 points
self.assertEqual(self.cmap.get_npoints('1_2_1'), 5.3)
self.assertEqual(self.cmap.get_npoints('2_2_1'), 1)
self.assertEqual(self.cmap.get_npoints('3_2_1'), 5)
self.assertEqual(self.cmap.get_npoints('4_2_1'), 0)
self.assertEqual(self.cmap.get_npoints('5_2_1'), 0)
self.assertEqual(self.cmap.get_npoints('6_2_1'), 2.5)
self.assertEqual(self.cmap.get_npoints('7_2_1'), 1)
def test_set_overall_message(self):
......
......@@ -24,7 +24,6 @@
$annotation-yellow: rgba(255,255,10,0.3);
$color-copy-tip: rgb(100,100,100);
$correct: $green-d1;
$partiallycorrect: $green-d1;
$incorrect: $red;
// +Extends - Capa
......@@ -76,11 +75,6 @@ h2 {
color: $correct;
}
.feedback-hint-partially-correct {
margin-top: ($baseline/2);
color: $partiallycorrect;
}
.feedback-hint-incorrect {
margin-top: ($baseline/2);
color: $incorrect;
......@@ -180,16 +174,6 @@ div.problem {
}
}
&.choicegroup_partially-correct {
@include status-icon($partiallycorrect, "\f00c");
border: 2px solid $partiallycorrect;
// keep green for correct answers on hover.
&:hover {
border-color: $partiallycorrect;
}
}
&.choicegroup_incorrect {
@include status-icon($incorrect, "\f00d");
border: 2px solid $incorrect;
......@@ -243,11 +227,6 @@ div.problem {
@include status-icon($correct, "\f00c");
}
// CASE: partially correct answer
&.partially-correct {
@include status-icon($partiallycorrect, "\f00c");
}
// CASE: incorrect answer
&.incorrect {
@include status-icon($incorrect, "\f00d");
......@@ -359,19 +338,6 @@ div.problem {
}
}
&.partially-correct, &.ui-icon-check {
p.status {
display: inline-block;
width: 25px;
height: 20px;
background: url('../images/partially-correct-icon.png') center center no-repeat;
}
input {
border-color: $partiallycorrect;
}
}
&.processing {
p.status {
display: inline-block;
......@@ -747,7 +713,7 @@ div.problem {
height: 46px;
}
> .incorrect, .partially-correct, .correct, .unanswered {
> .incorrect, .correct, .unanswered {
.status {
display: inline-block;
......@@ -768,18 +734,6 @@ div.problem {
}
}
// CASE: partially correct answer
> .partially-correct {
input {
border: 2px solid $partiallycorrect;
}
.status {
@include status-icon($partiallycorrect, "\f00c");
}
}
// CASE: correct answer
> .correct {
......@@ -821,7 +775,7 @@ div.problem {
.indicator-container {
display: inline-block;
.status.correct:after, .status.partially-correct:after, .status.incorrect:after, .status.unanswered:after {
.status.correct:after, .status.incorrect:after, .status.unanswered:after {
@include margin-left(0);
}
}
......@@ -987,20 +941,6 @@ div.problem {
}
}
.detailed-targeted-feedback-partially-correct {
> p:first-child {
@extend %t-strong;
color: $partiallycorrect;
text-transform: uppercase;
font-style: normal;
font-size: 0.9em;
}
p:last-child {
margin-bottom: 0;
}
}
.detailed-targeted-feedback-correct {
> p:first-child {
@extend %t-strong;
......@@ -1195,14 +1135,6 @@ div.problem {
}
}
.result-partially-correct {
background: url('../images/partially-correct-icon.png') left 20px no-repeat;
.result-actual-output {
color: #090;
}
}
.result-incorrect {
background: url('../images/incorrect-icon.png') left 20px no-repeat;
......@@ -1408,14 +1340,6 @@ div.problem {
}
}
label.choicetextgroup_partially-correct, section.choicetextgroup_partially-correct {
@extend label.choicegroup_partially-correct;
input[type="text"] {
border-color: $partiallycorrect;
}
}
label.choicetextgroup_incorrect, section.choicetextgroup_incorrect {
@extend label.choicegroup_incorrect;
}
......
......@@ -64,12 +64,6 @@ class ProblemPage(PageObject):
"""
self.q(css='div.problem div.capa_inputtype.textline input').fill(text)
def fill_answer_numerical(self, text):
"""
Fill in the answer to a numerical problem.
"""
self.q(css='div.problem section.inputtype input').fill(text)
def click_check(self):
"""
Click the Check button!
......@@ -90,24 +84,6 @@ class ProblemPage(PageObject):
"""
return self.q(css="div.problem div.capa_inputtype.textline div.correct span.status").is_present()
def simpleprob_is_correct(self):
"""
Is there a "correct" status showing? Works with simple problem types.
"""
return self.q(css="div.problem section.inputtype div.correct span.status").is_present()
def simpleprob_is_partially_correct(self):
"""
Is there a "partially correct" status showing? Works with simple problem types.
"""
return self.q(css="div.problem section.inputtype div.partially-correct span.status").is_present()
def simpleprob_is_incorrect(self):
"""
Is there an "incorrect" status showing? Works with simple problem types.
"""
return self.q(css="div.problem section.inputtype div.incorrect span.status").is_present()
def click_clarification(self, index=0):
"""
Click on an inline icon that can be included in problem text using an HTML <clarification> element:
......
......@@ -213,35 +213,3 @@ class ProblemWithMathjax(ProblemsTest):
self.assertIn("Hint (2 of 2): mathjax should work2", problem_page.hint_text)
self.assertTrue(problem_page.mathjax_rendered_in_hint, "MathJax did not rendered in problem hint")
class ProblemPartialCredit(ProblemsTest):
"""
Makes sure that the partial credit is appearing properly.
"""
def get_problem(self):
"""
Create a problem with partial credit.
"""
xml = dedent("""
<problem>
<p>The answer is 1. Partial credit for -1.</p>
<numericalresponse answer="1" partial_credit="list">
<formulaequationinput label="How many miles away from Earth is the sun? Use scientific notation to answer." />
<responseparam type="tolerance" default="0.01" />
<responseparam partial_answers="-1" />
</numericalresponse>
</problem>
""")
return XBlockFixtureDesc('problem', 'PARTIAL CREDIT TEST PROBLEM', data=xml)
def test_partial_credit(self):
"""
Test that we can see the partial credit value and feedback.
"""
self.courseware_page.visit()
problem_page = ProblemPage(self.browser)
self.assertEqual(problem_page.problem_name, 'PARTIAL CREDIT TEST PROBLEM')
problem_page.fill_answer_numerical('-1')
problem_page.click_check()
self.assertTrue(problem_page.simpleprob_is_partially_correct())
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