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
ee1953b3
Commit
ee1953b3
authored
Nov 18, 2013
by
polesye
Committed by
Alexander Kryklia
Jan 15, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
BLD-474: Allow multiple answers for string response.
parent
7b6cf0dc
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
175 additions
and
30 deletions
+175
-30
CHANGELOG.rst
+2
-0
common/lib/capa/capa/responsetypes.py
+92
-19
common/lib/capa/capa/tests/response_xml_factory.py
+14
-3
common/lib/capa/capa/tests/test_responsetypes.py
+0
-0
common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee
+57
-2
common/lib/xmodule/xmodule/js/src/problem/edit.coffee
+9
-5
docs/course_authors/source/appendices/e.rst
+0
-0
requirements/edx/github.txt
+1
-1
No files found.
CHANGELOG.rst
View file @
ee1953b3
...
...
@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
Blades: Allow regexp strings as the correct answer to a string response question. BLD-475.
Common: Add feature flags to allow developer use of pure XBlocks
- ALLOW_ALL_ADVANCED_COMPONENTS disables the hard-coded list of advanced
components in Studio, and allows any xblock to be added as an
...
...
common/lib/capa/capa/responsetypes.py
View file @
ee1953b3
...
...
@@ -329,8 +329,8 @@ class LoncapaResponse(object):
rephints
=
hintgroup
.
findall
(
self
.
hint_tag
)
hints_to_show
=
self
.
check_hint_condition
(
rephints
,
student_answers
)
# can be 'on_request' or 'always' (default)
hintmode
=
hintgroup
.
get
(
'mode'
,
'always'
)
for
hintpart
in
hintgroup
.
findall
(
'hintpart'
):
if
hintpart
.
get
(
'on'
)
in
hints_to_show
:
...
...
@@ -947,21 +947,35 @@ class NumericalResponse(LoncapaResponse):
class
StringResponse
(
LoncapaResponse
):
'''
This response type allows one or more answers. Use `_or_` separator to set
more than 1 answer.
This response type allows one or more answers.
Example:
Additional answers are added by `additional_answer` tag.
If `regexp` is in `type` attribute, than answers and hints are treated as regular expressions.
# One answer
Examples:
<stringresponse answer="Michigan">
<textline size="20" />
</stringresponse >
# Multiple answers
<stringresponse answer="Martin Luther King_or_Dr. Martin Luther King Jr.">
<textline size="20" />
<textline size="20" />
</stringresponse >
<stringresponse answer="a1" type="ci regexp">
<additional_answer>
\
d5</additional_answer>
<additional_answer>a3</additional_answer>
<textline size="20"/>
<hintgroup>
<stringhint answer="a0" type="ci" name="ha0" />
<stringhint answer="a4" type="ci" name="ha4" />
<stringhint answer="^
\
d" type="ci" name="re1" />
<hintpart on="ha0">
<startouttext />+1<endouttext />
</hintpart >
<hintpart on="ha4">
<startouttext />-1<endouttext />
</hintpart >
<hintpart on="re1">
<startouttext />Any number+5<endouttext />
</hintpart >
</hintgroup>
</stringresponse>
'''
response_tag
=
'stringresponse'
hint_tag
=
'stringhint'
...
...
@@ -969,11 +983,30 @@ class StringResponse(LoncapaResponse):
required_attributes
=
[
'answer'
]
max_inputfields
=
1
correct_answer
=
[]
SEPARATOR
=
'_or_'
def
setup_response_backward
(
self
):
self
.
correct_answer
=
[
contextualize_text
(
answer
,
self
.
context
)
.
strip
()
for
answer
in
self
.
xml
.
get
(
'answer'
)
.
split
(
'_or_'
)
]
def
setup_response
(
self
):
self
.
correct_answer
=
[
contextualize_text
(
answer
,
self
.
context
)
.
strip
()
for
answer
in
self
.
xml
.
get
(
'answer'
)
.
split
(
self
.
SEPARATOR
)]
self
.
backward
=
'_or_'
in
self
.
xml
.
get
(
'answer'
)
.
lower
()
self
.
regexp
=
'regexp'
in
self
.
xml
.
get
(
'type'
)
.
lower
()
.
split
(
' '
)
self
.
case_insensitive
=
'ci'
in
self
.
xml
.
get
(
'type'
)
.
lower
()
.
split
(
' '
)
# backward compatibility, can be removed in future, it is up to @Lyla Fisher.
if
self
.
backward
:
self
.
setup_response_backward
()
return
# end of backward compatibility
correct_answers
=
[
self
.
xml
.
get
(
'answer'
)]
+
[
el
.
text
for
el
in
self
.
xml
.
findall
(
'additional_answer'
)]
self
.
correct_answer
=
[
contextualize_text
(
answer
,
self
.
context
)
.
strip
()
for
answer
in
correct_answers
]
# remove additional_answer from xml, otherwise they will be displayed
for
el
in
self
.
xml
.
findall
(
'additional_answer'
):
self
.
xml
.
remove
(
el
)
def
get_score
(
self
,
student_answers
):
'''Grade a string response '''
...
...
@@ -981,21 +1014,61 @@ class StringResponse(LoncapaResponse):
correct
=
self
.
check_string
(
self
.
correct_answer
,
student_answer
)
return
CorrectMap
(
self
.
answer_id
,
'correct'
if
correct
else
'incorrect'
)
def
check_string
(
self
,
expected
,
given
):
if
self
.
xml
.
get
(
'type'
)
==
'ci'
:
def
check_string
_backward
(
self
,
expected
,
given
):
if
self
.
case_insensitive
:
return
given
.
lower
()
in
[
i
.
lower
()
for
i
in
expected
]
return
given
in
expected
def
check_string
(
self
,
expected
,
given
):
"""
Find given in expected.
If self.regexp is true, regular expression search is used.
if self.case_insensitive is true, case insensitive search is used, otherwise case sensitive search is used.
Spaces around values of attributes are stripped in XML parsing step.
Args:
expected: list.
given: str.
Returns: bool
Raises: `ResponseError` if it fails to compile regular expression.
Note: for old code, which supports _or_ separator, we add some backward compatibility handling.
Should be removed soon. When to remove it, is up to Lyla Fisher.
"""
# backward compatibility, should be removed in future.
if
self
.
backward
:
return
self
.
check_string_backward
(
expected
,
given
)
# end of backward compatibility
if
self
.
regexp
:
# regexp match
flags
=
re
.
IGNORECASE
if
self
.
case_insensitive
else
0
try
:
regexp
=
re
.
compile
(
'^'
+
'|'
.
join
(
expected
)
+
'$'
,
flags
=
flags
|
re
.
UNICODE
)
result
=
re
.
search
(
regexp
,
given
)
except
Exception
as
err
:
msg
=
'[courseware.capa.responsetypes.stringresponse] error: {}'
.
format
(
err
.
message
)
log
.
error
(
msg
,
exc_info
=
True
)
raise
ResponseError
(
msg
)
return
bool
(
result
)
else
:
# string match
if
self
.
case_insensitive
:
return
given
.
lower
()
in
[
i
.
lower
()
for
i
in
expected
]
else
:
return
given
in
expected
def
check_hint_condition
(
self
,
hxml_set
,
student_answers
):
given
=
student_answers
[
self
.
answer_id
]
.
strip
()
hints_to_show
=
[]
for
hxml
in
hxml_set
:
name
=
hxml
.
get
(
'name'
)
correct_answer
=
[
contextualize_text
(
answer
,
self
.
context
)
.
strip
()
for
answer
in
hxml
.
get
(
'answer'
)
.
split
(
self
.
SEPARATOR
)]
hinted_answer
=
contextualize_text
(
hxml
.
get
(
'answer'
),
self
.
context
)
.
strip
()
if
self
.
check_string
(
correct_answer
,
given
):
if
self
.
check_string
(
[
hinted_answer
]
,
given
):
hints_to_show
.
append
(
name
)
log
.
debug
(
'hints_to_show =
%
s'
,
hints_to_show
)
return
hints_to_show
...
...
common/lib/capa/capa/tests/response_xml_factory.py
View file @
ee1953b3
...
...
@@ -690,22 +690,30 @@ class StringResponseXMLFactory(ResponseXMLFactory):
*hintfn*: The name of a function in the script to use for hints.
*regexp*: Whether the response is regexp
*additional_answers*: list of additional asnwers.
"""
# Retrieve the **kwargs
answer
=
kwargs
.
get
(
"answer"
,
None
)
case_sensitive
=
kwargs
.
get
(
"case_sensitive"
,
True
)
hint_list
=
kwargs
.
get
(
'hints'
,
None
)
hint_fn
=
kwargs
.
get
(
'hintfn'
,
None
)
regexp
=
kwargs
.
get
(
'regexp'
,
None
)
additional_answers
=
kwargs
.
get
(
'additional_answers'
,
[])
assert
answer
# Create the <stringresponse> element
response_element
=
etree
.
Element
(
"stringresponse"
)
# Set the answer attribute
response_element
.
set
(
"answer"
,
str
(
answer
))
response_element
.
set
(
"answer"
,
unicode
(
answer
))
# Set the case sensitivity
response_element
.
set
(
"type"
,
"cs"
if
case_sensitive
else
"ci"
)
# Set the case sensitivity and regexp:
type_value
=
"cs"
if
case_sensitive
else
"ci"
type_value
+=
' regexp'
if
regexp
else
''
response_element
.
set
(
"type"
,
type_value
)
# Add the hints if specified
if
hint_list
or
hint_fn
:
...
...
@@ -727,6 +735,9 @@ class StringResponseXMLFactory(ResponseXMLFactory):
assert
not
hint_list
hintgroup_element
.
set
(
"hintfn"
,
hint_fn
)
for
additional_answer
in
additional_answers
:
etree
.
SubElement
(
response_element
,
"additional_answer"
)
.
text
=
additional_answer
return
response_element
def
create_input_element
(
self
,
**
kwargs
):
...
...
common/lib/capa/capa/tests/test_responsetypes.py
View file @
ee1953b3
This diff is collapsed.
Click to expand it.
common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee
View file @
ee1953b3
...
...
@@ -270,7 +270,7 @@ describe 'MarkdownEditingDescriptor', ->
<p>The answer is correct if it matches every character of the expected answer. This can be a problem with international spelling, dates, or anything where the format of the answer is not clear.</p>
<p>Which US state has Lansing as its capital?</p>
<stringresponse answer="Michigan" type="ci">
<stringresponse answer="Michigan" type="ci"
>
<textline size="20"/>
</stringresponse>
...
...
@@ -283,6 +283,29 @@ describe 'MarkdownEditingDescriptor', ->
</div>
</solution>
</problem>"""
)
it
'converts StringResponse with regular expression to xml'
,
->
data
=
MarkdownEditingDescriptor
.
markdownToXml
(
"""Who lead the civil right movement in the United States of America?
= |
\w
*
\.
?
\s
*Luther King
\s
*.*
[Explanation]
Test Explanation.
[Explanation]
"""
)
expect
(
data
).
toEqual
(
"""<problem>
<p>Who lead the civil right movement in the United States of America?</p>
<stringresponse answer="
\w
*
\.
?
\s
*Luther King
\s
*.*" type="ci regexp" >
<textline size="20"/>
</stringresponse>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
<p>Test Explanation.</p>
</div>
</solution>
</problem>"""
)
it
'converts StringResponse with multiple answers to xml'
,
->
data
=
MarkdownEditingDescriptor
.
markdownToXml
(
"""Who lead the civil right movement in the United States of America?
= Dr. Martin Luther King Jr.
...
...
@@ -296,7 +319,39 @@ describe 'MarkdownEditingDescriptor', ->
"""
)
expect
(
data
).
toEqual
(
"""<problem>
<p>Who lead the civil right movement in the United States of America?</p>
<stringresponse answer="Dr. Martin Luther King Jr._or_Doctor Martin Luther King Junior_or_Martin Luther King_or_Martin Luther King Junior" type="ci">
<stringresponse answer="Dr. Martin Luther King Jr." type="ci" >
<additional_answer>Doctor Martin Luther King Junior</additional_answer>
<additional_answer>Martin Luther King</additional_answer>
<additional_answer>Martin Luther King Junior</additional_answer>
<textline size="20"/>
</stringresponse>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
<p>Test Explanation.</p>
</div>
</solution>
</problem>"""
)
it
'converts StringResponse with multiple answers and regular expressions to xml'
,
->
data
=
MarkdownEditingDescriptor
.
markdownToXml
(
"""Write a number from 1 to 4.
=| ^One$
or= two
or= ^thre+
or= ^4|Four$
[Explanation]
Test Explanation.
[Explanation]
"""
)
expect
(
data
).
toEqual
(
"""<problem>
<p>Write a number from 1 to 4.</p>
<stringresponse answer="^One$" type="ci regexp" >
<additional_answer>two</additional_answer>
<additional_answer>^thre+</additional_answer>
<additional_answer>^4|Four$</additional_answer>
<textline size="20"/>
</stringresponse>
...
...
common/lib/xmodule/xmodule/js/src/problem/edit.coffee
View file @
ee1953b3
...
...
@@ -247,13 +247,17 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
string
+=
' <formulaequationinput />
\n
'
;
string
+=
'</numericalresponse>
\n\n
'
;
}
else
{
var
answers
=
[];
var
firstAnswer
=
answersList
.
shift
();
if
(
firstAnswer
[
0
]
===
'|'
)
{
//
this
is
regexp
case
string
=
'<stringresponse answer="'
+
firstAnswer
.
slice
(
1
).
trim
()
+
'" type="ci regexp" >
\n
'
}
else
{
string
=
'<stringresponse answer="'
+
firstAnswer
+
'" type="ci" >
\n
'
}
for
(
var
i
=
0
;
i
<
answersList
.
length
;
i
++
)
{
answers
.
push
(
answersList
[
i
])
string
+=
' <additional_answer>'
+
answersList
[
i
]
+
'</additional_answer>
\n
'
}
string
=
'<stringresponse answer="'
+
answers
.
join
(
'_or_'
)
+
'" type="ci">
\n
<textline size="20"/>
\n
</stringresponse>
\n\n
'
;
string
+=
' <textline size="20"/>
\n
</stringresponse>
\n\n
'
;
}
return
string
;
});
...
...
docs/course_authors/source/appendices/e.rst
View file @
ee1953b3
This diff is collapsed.
Click to expand it.
requirements/edx/github.txt
View file @
ee1953b3
...
...
@@ -17,7 +17,7 @@
# Our libraries:
-e git+https://github.com/edx/XBlock.git@cd77808aadd3ea1c2027ca8c0aa5624d8ccccc52#egg=XBlock
-e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail
-e git+https://github.com/edx/diff-cover.git@v0.2.
6
#egg=diff_cover
-e git+https://github.com/edx/diff-cover.git@v0.2.
9
#egg=diff_cover
-e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool
-e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle
-e git+https://github.com/edx/event-tracking.git@f0211d702d#egg=event-tracking
...
...
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