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
7aa80f63
Commit
7aa80f63
authored
Oct 31, 2013
by
Sarina Canelake
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1554 from edx/sarina/fix-violations
Clean up pep8/pylint
parents
9b3bc84c
d711d29d
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
151 additions
and
108 deletions
+151
-108
common/lib/capa/capa/responsetypes.py
+151
-108
No files found.
common/lib/capa/capa/responsetypes.py
View file @
7aa80f63
...
...
@@ -35,17 +35,17 @@ from calc import evaluator, UndefinedVariable
from
.
import
correctmap
from
datetime
import
datetime
from
pytz
import
UTC
from
.util
import
*
from
.util
import
compare_with_tolerance
,
contextualize_text
,
convert_files_to_filenames
,
is_list_of_files
,
find_with_default
from
lxml
import
etree
from
lxml.html.soupparser
import
fromstring
as
fromstring_bs
# uses Beautiful Soup!!! FIXME?
import
capa.xqueue_interface
as
xqueue_interface
import
safe_exec
import
capa.safe_exec
as
safe_exec
log
=
logging
.
getLogger
(
__name__
)
CorrectMap
=
correctmap
.
CorrectMap
CorrectMap
=
correctmap
.
CorrectMap
# pylint: disable=C0103
CORRECTMAP_PY
=
None
...
...
@@ -1181,7 +1181,7 @@ class CustomResponse(LoncapaResponse):
fn
=
self
.
code
answer_given
=
submission
[
0
]
if
(
len
(
idset
)
==
1
)
else
submission
kwnames
=
self
.
xml
.
get
(
"cfn_extra_args"
,
""
)
.
split
()
kwargs
=
{
n
:
self
.
context
.
get
(
n
)
for
n
in
kwnames
}
kwargs
=
{
n
:
self
.
context
.
get
(
n
)
for
n
in
kwnames
}
log
.
debug
(
" submission =
%
s"
%
submission
)
try
:
ret
=
fn
(
self
.
expect
,
answer_given
,
**
kwargs
)
...
...
@@ -1304,7 +1304,7 @@ class CustomResponse(LoncapaResponse):
# Notify student with a student input error
_
,
_
,
traceback_obj
=
sys
.
exc_info
()
raise
ResponseError
,
err
.
message
,
traceback_obj
raise
ResponseError
(
err
.
message
,
traceback_obj
)
#-----------------------------------------------------------------------------
...
...
@@ -1597,15 +1597,25 @@ class CodeResponse(LoncapaResponse):
class
ExternalResponse
(
LoncapaResponse
):
'''
"""
Grade the students input using an external server.
Typically used by coding problems.
'''
"""
response_tag
=
'externalresponse'
allowed_inputfields
=
[
'textline'
,
'textbox'
]
awdmap
=
{
'EXACT_ANS'
:
'correct'
,
# TODO: handle other loncapa responses
'WRONG_FORMAT'
:
'incorrect'
,
}
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
url
=
''
self
.
tests
=
[]
self
.
code
=
''
super
(
ExternalResponse
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
setup_response
(
self
):
xml
=
self
.
xml
...
...
@@ -1633,45 +1643,44 @@ class ExternalResponse(LoncapaResponse):
self
.
tests
=
xml
.
get
(
'tests'
)
def
do_external_request
(
self
,
cmd
,
extra_payload
):
'''
"""
Perform HTTP request / post to external server.
cmd = remote command to perform (str)
extra_payload = dict of extra stuff to post.
Return XML tree of response (from response body)
'''
"""
xmlstr
=
etree
.
tostring
(
self
.
xml
,
pretty_print
=
True
)
payload
=
{
'xml'
:
xmlstr
,
'edX_cmd'
:
cmd
,
'edX_tests'
:
self
.
tests
,
'processor'
:
self
.
code
,
}
payload
=
{
'xml'
:
xmlstr
,
'edX_cmd'
:
cmd
,
'edX_tests'
:
self
.
tests
,
'processor'
:
self
.
code
,
}
payload
.
update
(
extra_payload
)
try
:
# call external server. TODO: synchronous call, can block for a
# long time
r
=
requests
.
post
(
self
.
url
,
data
=
payload
)
r
eq
=
requests
.
post
(
self
.
url
,
data
=
payload
)
except
Exception
as
err
:
msg
=
'Error
%
s - cannot connect to external server url=
%
s'
%
(
err
,
self
.
url
)
msg
=
'Error {0} - cannot connect to external server url={1}'
.
format
(
err
,
self
.
url
)
log
.
error
(
msg
)
raise
Exception
(
msg
)
if
self
.
system
.
DEBUG
:
log
.
info
(
'response =
%
s'
%
r
.
text
)
log
.
info
(
'response =
%
s'
,
req
.
text
)
if
(
not
r
.
text
)
or
(
not
r
.
text
.
strip
()):
if
(
not
r
eq
.
text
)
or
(
not
req
.
text
.
strip
()):
raise
Exception
(
'Error: no response from external server url=
%
s'
%
self
.
url
)
try
:
# response is XML; parse it
rxml
=
etree
.
fromstring
(
r
.
text
)
rxml
=
etree
.
fromstring
(
r
eq
.
text
)
except
Exception
as
err
:
msg
=
'Error
%
s - cannot parse response from external server r.text=
%
s'
%
(
err
,
r
.
text
)
msg
=
'Error {0} - cannot parse response from external server req.text={1}'
.
format
(
err
,
req
.
text
)
log
.
error
(
msg
)
raise
Exception
(
msg
)
...
...
@@ -1682,9 +1691,13 @@ class ExternalResponse(LoncapaResponse):
cmap
=
CorrectMap
()
try
:
submission
=
[
student_answers
[
k
]
for
k
in
idset
]
except
Exception
as
err
:
log
.
error
(
'Error
%
s: cannot get student answer for
%
s; student_answers=
%
s'
%
(
err
,
self
.
answer_ids
,
student_answers
))
except
Exception
as
err
:
# pylint: disable=W0703
log
.
error
(
'Error
%
s: cannot get student answer for
%
s; student_answers=
%
s'
,
err
,
self
.
answer_ids
,
student_answers
)
raise
Exception
(
err
)
self
.
context
.
update
({
'submission'
:
submission
})
...
...
@@ -1693,8 +1706,8 @@ class ExternalResponse(LoncapaResponse):
try
:
rxml
=
self
.
do_external_request
(
'get_score'
,
extra_payload
)
except
Exception
as
err
:
log
.
error
(
'Error
%
s'
%
err
)
except
Exception
as
err
:
# pylint: disable=W0703
log
.
error
(
'Error
%
s'
,
err
)
if
self
.
system
.
DEBUG
:
cmap
.
set_dict
(
dict
(
zip
(
sorted
(
self
.
answer_ids
),
[
'incorrect'
]
*
len
(
idset
))))
...
...
@@ -1703,13 +1716,11 @@ class ExternalResponse(LoncapaResponse):
'<span class="inline-error">
%
s</span>'
%
str
(
err
)
.
replace
(
'<'
,
'<'
))
return
cmap
ad
=
rxml
.
find
(
'awarddetail'
)
.
text
admap
=
{
'EXACT_ANS'
:
'correct'
,
# TODO: handle other loncapa responses
'WRONG_FORMAT'
:
'incorrect'
,
}
awd
=
rxml
.
find
(
'awarddetail'
)
.
text
self
.
context
[
'correct'
]
=
[
'correct'
]
if
a
d
in
a
dmap
:
self
.
context
[
'correct'
][
0
]
=
admap
[
a
d
]
if
a
wd
in
self
.
aw
dmap
:
self
.
context
[
'correct'
][
0
]
=
self
.
awdmap
[
aw
d
]
# create CorrectMap
for
key
in
idset
:
...
...
@@ -1721,14 +1732,14 @@ class ExternalResponse(LoncapaResponse):
return
cmap
def
get_answers
(
self
):
'''
"""
Use external server to get expected answers
'''
"""
try
:
rxml
=
self
.
do_external_request
(
'get_answers'
,
{})
exans
=
json
.
loads
(
rxml
.
find
(
'expected'
)
.
text
)
except
Exception
as
err
:
log
.
error
(
'Error
%
s'
%
err
)
except
Exception
as
err
:
# pylint: disable=W0703
log
.
error
(
'Error
%
s'
,
err
)
if
self
.
system
.
DEBUG
:
msg
=
'<span class="inline-error">
%
s</span>'
%
str
(
err
)
.
replace
(
'<'
,
'<'
)
...
...
@@ -1736,8 +1747,8 @@ class ExternalResponse(LoncapaResponse):
exans
[
0
]
=
msg
if
not
(
len
(
exans
)
==
len
(
self
.
answer_ids
)):
log
.
error
(
'Expected
%
d answers from external server, only got
%
d!'
%
(
len
(
self
.
answer_ids
),
len
(
exans
)
))
log
.
error
(
'Expected
%
s answers from external server, only got
%
s!'
,
len
(
self
.
answer_ids
),
len
(
exans
))
raise
Exception
(
'Short response from external server'
)
return
dict
(
zip
(
self
.
answer_ids
,
exans
))
...
...
@@ -1745,9 +1756,9 @@ class ExternalResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
class
FormulaResponse
(
LoncapaResponse
):
'''
"""
Checking of symbolic math response using numerical sampling.
'''
"""
response_tag
=
'formularesponse'
hint_tag
=
'formulahint'
...
...
@@ -1776,11 +1787,11 @@ class FormulaResponse(LoncapaResponse):
if
tolerance_xml
:
# If it isn't an empty list...
self
.
tolerance
=
contextualize_text
(
tolerance_xml
[
0
],
context
)
ts
=
xml
.
get
(
'type'
)
if
ts
is
None
:
t
ype
s
=
xml
.
get
(
'type'
)
if
t
ype
s
is
None
:
typeslist
=
[]
else
:
typeslist
=
ts
.
split
(
','
)
typeslist
=
t
ype
s
.
split
(
','
)
if
'ci'
in
typeslist
:
# Case insensitive
self
.
case_sensitive
=
False
...
...
@@ -1812,30 +1823,33 @@ class FormulaResponse(LoncapaResponse):
answer
,
case_sensitive
=
self
.
case_sensitive
,
))
except
UndefinedVariable
as
uv
:
except
UndefinedVariable
as
err
:
log
.
debug
(
'formularesponse: undefined variable in formula=
%
s'
%
answer
)
'formularesponse: undefined variable in formula=
%
s'
,
cgi
.
escape
(
answer
)
)
raise
StudentInputError
(
"Invalid input: "
+
uv
.
message
+
" not permitted in answer"
"Invalid input: "
+
err
.
message
+
" not permitted in answer"
)
except
ValueError
as
ve
:
if
'factorial'
in
ve
.
message
:
except
ValueError
as
err
:
if
'factorial'
in
err
.
message
:
# This is thrown when fact() or factorial() is used in a formularesponse answer
# that tests on negative and/or non-integer inputs
#
ve
.message will be: `factorial() only accepts integral values` or
#
err
.message will be: `factorial() only accepts integral values` or
# `factorial() not defined for negative values`
log
.
debug
(
(
'formularesponse: factorial function used in response '
'that tests negative and/or non-integer inputs. '
'given={0}'
)
.
format
(
given
)
'Provided answer was:
%
s'
),
cgi
.
escape
(
answer
)
)
raise
StudentInputError
(
(
"factorial function not permitted in answer "
"for this problem. Provided answer was: "
"{0}"
)
.
format
(
cgi
.
escape
(
given
))
"{0}"
)
.
format
(
cgi
.
escape
(
answer
))
)
# If non-factorial related ValueError thrown, handle it the same as any other Exception
log
.
debug
(
'formularesponse: error
{0} in formula'
.
format
(
ve
)
)
log
.
debug
(
'formularesponse: error
%
s in formula'
,
err
)
raise
StudentInputError
(
"Invalid input: Could not parse '
%
s' as a formula"
%
cgi
.
escape
(
answer
))
except
Exception
as
err
:
...
...
@@ -1857,7 +1871,7 @@ class FormulaResponse(LoncapaResponse):
ranges
=
dict
(
zip
(
variables
,
sranges
))
out
=
[]
for
i
in
range
(
numsamples
):
for
_
in
range
(
numsamples
):
var_dict
=
{}
# ranges give numerical ranges for testing
for
var
in
ranges
:
...
...
@@ -1902,15 +1916,17 @@ class FormulaResponse(LoncapaResponse):
except
StudentInputError
:
return
False
def
strip_dict
(
self
,
d
):
''' Takes a dict. Returns an identical dict, with all non-word
def
strip_dict
(
self
,
inp_d
):
"""
Takes a dict. Returns an identical dict, with all non-word
keys and all non-numeric values stripped out. All values also
converted to float. Used so we can safely use Python contexts.
'''
d
=
dict
([(
k
,
numpy
.
complex
(
d
[
k
]))
for
k
in
d
if
type
(
k
)
==
str
and
k
.
isalnum
()
and
isinstance
(
d
[
k
],
numbers
.
Number
)])
return
d
"""
inp_d
=
dict
([(
k
,
numpy
.
complex
(
inp_d
[
k
]))
for
k
in
inp_d
if
type
(
k
)
==
str
and
k
.
isalnum
()
and
isinstance
(
inp_d
[
k
],
numbers
.
Number
)])
return
inp_d
def
check_hint_condition
(
self
,
hxml_set
,
student_answers
):
given
=
student_answers
[
self
.
answer_id
]
...
...
@@ -1920,14 +1936,18 @@ class FormulaResponse(LoncapaResponse):
name
=
hxml
.
get
(
'name'
)
correct_answer
=
contextualize_text
(
hxml
.
get
(
'answer'
),
self
.
context
)
# pylint: disable=W0703
try
:
correctness
=
self
.
check_formula
(
correct_answer
,
given
,
samples
)
correct_answer
,
given
,
samples
)
except
Exception
:
correctness
=
'incorrect'
if
correctness
==
'correct'
:
hints_to_show
.
append
(
name
)
log
.
debug
(
'hints_to_show =
%
s'
%
hints_to_show
)
log
.
debug
(
'hints_to_show =
%
s'
,
hints_to_show
)
return
hints_to_show
def
get_answers
(
self
):
...
...
@@ -1937,10 +1957,16 @@ class FormulaResponse(LoncapaResponse):
class
SchematicResponse
(
LoncapaResponse
):
"""
Circuit schematic response type.
"""
response_tag
=
'schematicresponse'
allowed_inputfields
=
[
'schematic'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
code
=
''
super
(
SchematicResponse
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
setup_response
(
self
):
xml
=
self
.
xml
answer
=
xml
.
xpath
(
'//*[@id=$id]//answer'
,
id
=
xml
.
get
(
'id'
))[
0
]
...
...
@@ -2010,6 +2036,10 @@ class ImageResponse(LoncapaResponse):
response_tag
=
'imageresponse'
allowed_inputfields
=
[
'imageinput'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
ielements
=
[]
super
(
ImageResponse
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
setup_response
(
self
):
self
.
ielements
=
self
.
inputfields
self
.
answer_ids
=
[
ie
.
get
(
'id'
)
for
ie
in
self
.
ielements
]
...
...
@@ -2018,40 +2048,39 @@ class ImageResponse(LoncapaResponse):
correct_map
=
CorrectMap
()
expectedset
=
self
.
get_mapped_answers
()
for
aid
in
self
.
answer_ids
:
# loop through IDs of <imageinput>
# fields in our stanza
given
=
student_answers
[
aid
]
# this should be a string of the form '[x,y]'
# Fields in our stanza
given
=
student_answers
[
aid
]
# This should be a string of the form '[x,y]'
correct_map
.
set
(
aid
,
'incorrect'
)
if
not
given
:
# No answer to parse. Mark as incorrect and move on
continue
#
p
arse given answer
m
=
re
.
match
(
r'\[([0-9]+),([0-9]+)]'
,
given
.
strip
()
.
replace
(
' '
,
''
))
if
not
m
:
#
P
arse given answer
acoords
=
re
.
match
(
r'\[([0-9]+),([0-9]+)]'
,
given
.
strip
()
.
replace
(
' '
,
''
))
if
not
acoords
:
raise
Exception
(
'[capamodule.capa.responsetypes.imageinput] '
'error grading
%
s (input=
%
s)'
%
(
aid
,
given
))
(
gx
,
gy
)
=
[
int
(
x
)
for
x
in
m
.
groups
()]
'error grading
{0} (input={1})'
.
format
(
aid
,
given
))
(
ans_x
,
ans_y
)
=
[
int
(
x
)
for
x
in
acoords
.
groups
()]
rectangles
,
regions
=
expectedset
if
rectangles
[
aid
]:
#
r
ectangles part - for backward compatibility
if
rectangles
[
aid
]:
#
R
ectangles part - for backward compatibility
# Check whether given point lies in any of the solution
# rectangles
solution_rectangles
=
rectangles
[
aid
]
.
split
(
';'
)
for
solution_rectangle
in
solution_rectangles
:
# parse expected answer
# TODO: Compile regexp on file load
m
=
re
.
match
(
sr_coords
=
re
.
match
(
r'[\(\[]([0-9]+),([0-9]+)[\)\]]-[\(\[]([0-9]+),([0-9]+)[\)\]]'
,
solution_rectangle
.
strip
()
.
replace
(
' '
,
''
))
if
not
m
:
if
not
sr_coords
:
msg
=
'Error in problem specification! cannot parse rectangle in
%
s'
%
(
etree
.
tostring
(
self
.
ielements
[
aid
],
pretty_print
=
True
))
raise
Exception
(
'[capamodule.capa.responsetypes.imageinput] '
+
msg
)
(
llx
,
lly
,
urx
,
ury
)
=
[
int
(
x
)
for
x
in
m
.
groups
()]
(
llx
,
lly
,
urx
,
ury
)
=
[
int
(
x
)
for
x
in
sr_coords
.
groups
()]
# answer is correct if (x,y) is within the specified
# rectangle
if
(
llx
<=
gx
<=
urx
)
and
(
lly
<=
g
y
<=
ury
):
if
(
llx
<=
ans_x
<=
urx
)
and
(
lly
<=
ans_
y
<=
ury
):
correct_map
.
set
(
aid
,
'correct'
)
break
if
correct_map
[
aid
][
'correctness'
]
!=
'correct'
and
regions
[
aid
]:
...
...
@@ -2065,13 +2094,13 @@ class ImageResponse(LoncapaResponse):
for
region
in
parsed_region
:
polygon
=
MultiPoint
(
region
)
.
convex_hull
if
(
polygon
.
type
==
'Polygon'
and
polygon
.
contains
(
Point
(
gx
,
g
y
))):
polygon
.
contains
(
Point
(
ans_x
,
ans_
y
))):
correct_map
.
set
(
aid
,
'correct'
)
break
return
correct_map
def
get_mapped_answers
(
self
):
'''
"""
Returns the internal representation of the answers
Input:
...
...
@@ -2080,7 +2109,7 @@ class ImageResponse(LoncapaResponse):
tuple (dict, dict) -
rectangles (dict) - a map of inputs to the defined rectangle for that input
regions (dict) - a map of inputs to the defined region for that input
'''
"""
answers
=
(
dict
([(
ie
.
get
(
'id'
),
ie
.
get
(
'rectangle'
))
for
ie
in
self
.
ielements
]),
...
...
@@ -2088,7 +2117,7 @@ class ImageResponse(LoncapaResponse):
return
answers
def
get_answers
(
self
):
'''
"""
Returns the external representation of the answers
Input:
...
...
@@ -2096,11 +2125,11 @@ class ImageResponse(LoncapaResponse):
Returns:
dict (str, (str, str)) - a map of inputs to a tuple of their rectange
and their regions
'''
"""
answers
=
{}
for
ie
in
self
.
ielements
:
ie_id
=
ie
.
get
(
'id'
)
answers
[
ie_id
]
=
(
ie
.
get
(
'rectangle'
),
ie
.
get
(
'regions'
))
for
ie
lt
in
self
.
ielements
:
ie_id
=
ie
lt
.
get
(
'id'
)
answers
[
ie_id
]
=
(
ie
lt
.
get
(
'rectangle'
),
ielt
.
get
(
'regions'
))
return
answers
...
...
@@ -2108,26 +2137,32 @@ class ImageResponse(LoncapaResponse):
class
AnnotationResponse
(
LoncapaResponse
):
'''
"""
Checking of annotation responses.
The response contains both a comment (student commentary) and an option (student tag).
Only the tag is currently graded. Answers may be incorrect, partially correct, or correct.
'''
"""
response_tag
=
'annotationresponse'
allowed_inputfields
=
[
'annotationinput'
]
max_inputfields
=
1
default_scoring
=
{
'incorrect'
:
0
,
'partially-correct'
:
1
,
'correct'
:
2
}
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
scoring_map
=
{}
self
.
answer_map
=
{}
super
(
AnnotationResponse
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
setup_response
(
self
):
xml
=
self
.
xml
self
.
scoring_map
=
self
.
_get_scoring_map
()
self
.
answer_map
=
self
.
_get_answer_map
()
self
.
maxpoints
=
self
.
_get_max_points
()
def
get_score
(
self
,
student_answers
):
''' Returns a CorrectMap for the student answer, which may include
partially correct answers.'''
"""
Returns a CorrectMap for the student answer, which may include
partially correct answers.
"""
student_answer
=
student_answers
[
self
.
answer_id
]
student_option
=
self
.
_get_submitted_option_id
(
student_answer
)
...
...
@@ -2146,23 +2181,26 @@ class AnnotationResponse(LoncapaResponse):
return
self
.
answer_map
def
_get_scoring_map
(
self
):
''' Returns a dict of option->scoring for each input. '''
"""Returns a dict of option->scoring for each input."""
scoring
=
self
.
default_scoring
choices
=
dict
([(
choice
,
choice
)
for
choice
in
scoring
])
scoring_map
=
{}
for
inputfield
in
self
.
inputfields
:
option_scoring
=
dict
([(
option
[
'id'
],
{
option_scoring
=
dict
([(
option
[
'id'
],
{
'correctness'
:
choices
.
get
(
option
[
'choice'
]),
'points'
:
scoring
.
get
(
option
[
'choice'
])
})
for
option
in
self
.
_find_options
(
inputfield
)])
}
)
for
option
in
self
.
_find_options
(
inputfield
)])
scoring_map
[
inputfield
.
get
(
'id'
)]
=
option_scoring
return
scoring_map
def
_get_answer_map
(
self
):
''' Returns a dict of answers for each input.'''
"""Returns a dict of answers for each input."""
answer_map
=
{}
for
inputfield
in
self
.
inputfields
:
correct_option
=
self
.
_find_option_with_choice
(
...
...
@@ -2173,13 +2211,13 @@ class AnnotationResponse(LoncapaResponse):
return
answer_map
def
_get_max_points
(
self
):
''' Returns a dict of the max points for each input: input id -> maxpoints. '''
"""Returns a dict of the max points for each input: input id -> maxpoints."""
scoring
=
self
.
default_scoring
correct_points
=
scoring
.
get
(
'correct'
)
return
dict
([(
inputfield
.
get
(
'id'
),
correct_points
)
for
inputfield
in
self
.
inputfields
])
def
_find_options
(
self
,
inputfield
):
''' Returns an array of dicts where each dict represents an option. '''
"""Returns an array of dicts where each dict represents an option. """
elements
=
inputfield
.
findall
(
'./options/option'
)
return
[{
'id'
:
index
,
...
...
@@ -2188,22 +2226,22 @@ class AnnotationResponse(LoncapaResponse):
}
for
(
index
,
option
)
in
enumerate
(
elements
)]
def
_find_option_with_choice
(
self
,
inputfield
,
choice
):
''' Returns the option with the given choice value, otherwise None. '''
"""Returns the option with the given choice value, otherwise None. """
for
option
in
self
.
_find_options
(
inputfield
):
if
option
[
'choice'
]
==
choice
:
return
option
def
_unpack
(
self
,
json_value
):
''' Unpacks a student response value submitted as JSON.'''
d
=
json
.
loads
(
json_value
)
if
type
(
d
)
!=
dict
:
d
=
{}
"""Unpacks a student response value submitted as JSON."""
json_
d
=
json
.
loads
(
json_value
)
if
type
(
json_
d
)
!=
dict
:
json_
d
=
{}
comment_value
=
d
.
get
(
'comment'
,
''
)
if
not
isinstance
(
d
,
basestring
):
comment_value
=
json_
d
.
get
(
'comment'
,
''
)
if
not
isinstance
(
json_
d
,
basestring
):
comment_value
=
''
options_value
=
d
.
get
(
'options'
,
[])
options_value
=
json_
d
.
get
(
'options'
,
[])
if
not
isinstance
(
options_value
,
list
):
options_value
=
[]
...
...
@@ -2213,7 +2251,7 @@ class AnnotationResponse(LoncapaResponse):
}
def
_get_submitted_option_id
(
self
,
student_answer
):
''' Return the single option that was selected, otherwise None.'''
"""Return the single option that was selected, otherwise None."""
submitted
=
self
.
_unpack
(
student_answer
)
option_ids
=
submitted
[
'options_value'
]
if
len
(
option_ids
)
==
1
:
...
...
@@ -2235,6 +2273,12 @@ class ChoiceTextResponse(LoncapaResponse):
'radiotextgroup'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
correct_inputs
=
{}
self
.
answer_values
=
{}
self
.
correct_choices
=
{}
super
(
ChoiceTextResponse
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
setup_response
(
self
):
"""
Sets up three dictionaries for use later:
...
...
@@ -2250,10 +2294,8 @@ class ChoiceTextResponse(LoncapaResponse):
"""
context
=
self
.
context
self
.
correct_choices
=
{}
self
.
assign_choice_names
()
self
.
correct_inputs
=
{}
self
.
answer_values
=
{
self
.
answer_id
:
[]}
self
.
assign_choice_names
()
correct_xml
=
self
.
xml
.
xpath
(
'//*[@id=$id]//choice[@correct="true"]'
,
id
=
self
.
xml
.
get
(
'id'
))
for
node
in
correct_xml
:
...
...
@@ -2552,6 +2594,7 @@ class ChoiceTextResponse(LoncapaResponse):
# TEMPORARY: List of all response subclasses
# FIXME: To be replaced by auto-registration
# pylint: disable=E0604
__all__
=
[
CodeResponse
,
NumericalResponse
,
FormulaResponse
,
...
...
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