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
f78be581
Commit
f78be581
authored
Jun 07, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cleaning up pep8 issues, including extraneous imports
parent
f2309b31
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
124 additions
and
128 deletions
+124
-128
common/lib/capa/capa_problem.py
+124
-128
No files found.
common/lib/capa/capa_problem.py
View file @
f78be581
...
@@ -12,7 +12,6 @@ import logging
...
@@ -12,7 +12,6 @@ import logging
import
math
import
math
import
numpy
import
numpy
import
os
import
os
import
os.path
import
random
import
random
import
re
import
re
import
scipy
import
scipy
...
@@ -20,58 +19,58 @@ import struct
...
@@ -20,58 +19,58 @@ import struct
from
lxml
import
etree
from
lxml
import
etree
from
lxml.etree
import
Element
from
lxml.etree
import
Element
from
xml.sax.saxutils
import
escape
,
unescape
from
xml.sax.saxutils
import
unescape
from
util
import
contextualize_text
from
util
import
contextualize_text
import
inputtypes
import
inputtypes
from
responsetypes
import
NumericalResponse
,
FormulaResponse
,
CustomResponse
,
SchematicResponse
,
MultipleChoiceResponse
,
StudentInputError
,
TrueFalseResponse
,
ExternalResponse
,
ImageResponse
,
OptionResponse
,
SymbolicResponse
from
responsetypes
import
NumericalResponse
,
FormulaResponse
,
CustomResponse
,
SchematicResponse
,
MultipleChoiceResponse
,
TrueFalseResponse
,
ExternalResponse
,
ImageResponse
,
OptionResponse
,
SymbolicResponse
import
calc
import
calc
import
eia
import
eia
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
response_types
=
{
'numericalresponse'
:
NumericalResponse
,
response_types
=
{
'numericalresponse'
:
NumericalResponse
,
'formularesponse'
:
FormulaResponse
,
'formularesponse'
:
FormulaResponse
,
'customresponse'
:
CustomResponse
,
'customresponse'
:
CustomResponse
,
'schematicresponse'
:
SchematicResponse
,
'schematicresponse'
:
SchematicResponse
,
'externalresponse'
:
ExternalResponse
,
'externalresponse'
:
ExternalResponse
,
'multiplechoiceresponse'
:
MultipleChoiceResponse
,
'multiplechoiceresponse'
:
MultipleChoiceResponse
,
'truefalseresponse'
:
TrueFalseResponse
,
'truefalseresponse'
:
TrueFalseResponse
,
'imageresponse'
:
ImageResponse
,
'imageresponse'
:
ImageResponse
,
'optionresponse'
:
OptionResponse
,
'optionresponse'
:
OptionResponse
,
'symbolicresponse'
:
SymbolicResponse
,
'symbolicresponse'
:
SymbolicResponse
,
}
}
entry_types
=
[
'textline'
,
'schematic'
,
'choicegroup'
,
'textbox'
,
'imageinput'
,
'optioninput'
]
entry_types
=
[
'textline'
,
'schematic'
,
'choicegroup'
,
'textbox'
,
'imageinput'
,
'optioninput'
]
solution_types
=
[
'solution'
]
# extra things displayed after "show answers" is pressed
solution_types
=
[
'solution'
]
# extra things displayed after "show answers" is pressed
response_properties
=
[
"responseparam"
,
"answer"
]
# these get captured as student responses
response_properties
=
[
"responseparam"
,
"answer"
]
# these get captured as student responses
# How to convert from original XML to HTML
# How to convert from original XML to HTML
# We should do this with xlst later
# We should do this with xlst later
html_transforms
=
{
'problem'
:
{
'tag'
:
'div'
},
html_transforms
=
{
'problem'
:
{
'tag'
:
'div'
},
"numericalresponse"
:
{
'tag'
:
'span'
},
"numericalresponse"
:
{
'tag'
:
'span'
},
"customresponse"
:
{
'tag'
:
'span'
},
"customresponse"
:
{
'tag'
:
'span'
},
"externalresponse"
:
{
'tag'
:
'span'
},
"externalresponse"
:
{
'tag'
:
'span'
},
"schematicresponse"
:
{
'tag'
:
'span'
},
"schematicresponse"
:
{
'tag'
:
'span'
},
"formularesponse"
:
{
'tag'
:
'span'
},
"formularesponse"
:
{
'tag'
:
'span'
},
"symbolicresponse"
:
{
'tag'
:
'span'
},
"symbolicresponse"
:
{
'tag'
:
'span'
},
"multiplechoiceresponse"
:
{
'tag'
:
'span'
},
"multiplechoiceresponse"
:
{
'tag'
:
'span'
},
"text"
:
{
'tag'
:
'span'
},
"text"
:
{
'tag'
:
'span'
},
"math"
:
{
'tag'
:
'span'
},
"math"
:
{
'tag'
:
'span'
},
}
}
global_context
=
{
'random'
:
random
,
global_context
=
{
'random'
:
random
,
'numpy'
:
numpy
,
'numpy'
:
numpy
,
'math'
:
math
,
'math'
:
math
,
'scipy'
:
scipy
,
'scipy'
:
scipy
,
'calc'
:
calc
,
'calc'
:
calc
,
'eia'
:
eia
}
'eia'
:
eia
}
# These should be removed from HTML output, including all subelements
# These should be removed from HTML output, including all subelements
html_problem_semantics
=
[
"responseparam"
,
"answer"
,
"script"
]
html_problem_semantics
=
[
"responseparam"
,
"answer"
,
"script"
]
# These should be removed from HTML output, but keeping subelements
# These should be removed from HTML output, but keeping subelements
html_skip
=
[
"numericalresponse"
,
"customresponse"
,
"schematicresponse"
,
"formularesponse"
,
"text"
,
"externalresponse"
,
'symbolicresponse'
]
html_skip
=
[
"numericalresponse"
,
"customresponse"
,
"schematicresponse"
,
"formularesponse"
,
"text"
,
"externalresponse"
,
'symbolicresponse'
]
# removed in MC
# removed in MC
## These should be transformed
## These should be transformed
...
@@ -82,6 +81,7 @@ html_skip = ["numericalresponse", "customresponse", "schematicresponse", "formul
...
@@ -82,6 +81,7 @@ html_skip = ["numericalresponse", "customresponse", "schematicresponse", "formul
# "solution":inputtypes.solution.render,
# "solution":inputtypes.solution.render,
# }
# }
class
LoncapaProblem
(
object
):
class
LoncapaProblem
(
object
):
def
__init__
(
self
,
fileobject
,
id
,
state
=
None
,
seed
=
None
,
system
=
None
):
def
__init__
(
self
,
fileobject
,
id
,
state
=
None
,
seed
=
None
,
system
=
None
):
## Initialize class variables from state
## Initialize class variables from state
...
@@ -107,22 +107,22 @@ class LoncapaProblem(object):
...
@@ -107,22 +107,22 @@ class LoncapaProblem(object):
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
if
not
self
.
seed
:
if
not
self
.
seed
:
self
.
seed
=
struct
.
unpack
(
'i'
,
os
.
urandom
(
4
))[
0
]
self
.
seed
=
struct
.
unpack
(
'i'
,
os
.
urandom
(
4
))[
0
]
## Parse XML file
## Parse XML file
if
getattr
(
system
,
'DEBUG'
,
False
):
if
getattr
(
system
,
'DEBUG'
,
False
):
log
.
info
(
"[courseware.capa.capa_problem.lcp.init] fileobject =
%
s"
%
fileobject
)
log
.
info
(
"[courseware.capa.capa_problem.lcp.init] fileobject =
%
s"
%
fileobject
)
file_text
=
fileobject
.
read
()
file_text
=
fileobject
.
read
()
self
.
fileobject
=
fileobject
# save it, so we can use for debugging information later
self
.
fileobject
=
fileobject
# save it, so we can use for debugging information later
# Convert startouttext and endouttext to proper <text></text>
# Convert startouttext and endouttext to proper <text></text>
# TODO: Do with XML operations
# TODO: Do with XML operations
file_text
=
re
.
sub
(
"startouttext
\
s*/"
,
"text"
,
file_text
)
file_text
=
re
.
sub
(
"startouttext
\
s*/"
,
"text"
,
file_text
)
file_text
=
re
.
sub
(
"endouttext
\
s*/"
,
"/text"
,
file_text
)
file_text
=
re
.
sub
(
"endouttext
\
s*/"
,
"/text"
,
file_text
)
self
.
tree
=
etree
.
XML
(
file_text
)
self
.
tree
=
etree
.
XML
(
file_text
)
self
.
preprocess_problem
(
self
.
tree
,
correct_map
=
self
.
correct_map
,
answer_map
=
self
.
student_answers
)
self
.
preprocess_problem
(
self
.
tree
,
correct_map
=
self
.
correct_map
,
answer_map
=
self
.
student_answers
)
self
.
context
=
self
.
extract_context
(
self
.
tree
,
seed
=
self
.
seed
)
self
.
context
=
self
.
extract_context
(
self
.
tree
,
seed
=
self
.
seed
)
for
response
in
self
.
tree
.
xpath
(
'//'
+
"|//"
.
join
(
response_types
)):
for
response
in
self
.
tree
.
xpath
(
'//'
+
"|//"
.
join
(
response_types
)):
responder
=
response_types
[
response
.
tag
](
response
,
self
.
context
,
self
.
system
)
responder
=
response_types
[
response
.
tag
](
response
,
self
.
context
,
self
.
system
)
responder
.
preprocess_response
()
responder
.
preprocess_response
()
...
@@ -130,34 +130,34 @@ class LoncapaProblem(object):
...
@@ -130,34 +130,34 @@ class LoncapaProblem(object):
return
u"LoncapaProblem ({0})"
.
format
(
self
.
fileobject
)
return
u"LoncapaProblem ({0})"
.
format
(
self
.
fileobject
)
def
get_state
(
self
):
def
get_state
(
self
):
''' Stored per-user session data neeeded to:
''' Stored per-user session data neeeded to:
1) Recreate the problem
1) Recreate the problem
2) Populate any student answers. '''
2) Populate any student answers. '''
return
{
'seed'
:
self
.
seed
,
return
{
'seed'
:
self
.
seed
,
'student_answers'
:
self
.
student_answers
,
'student_answers'
:
self
.
student_answers
,
'correct_map'
:
self
.
correct_map
,
'correct_map'
:
self
.
correct_map
,
'done'
:
self
.
done
}
'done'
:
self
.
done
}
def
get_max_score
(
self
):
def
get_max_score
(
self
):
'''
'''
TODO: multiple points for programming problems.
TODO: multiple points for programming problems.
'''
'''
sum
=
0
sum
=
0
for
et
in
entry_types
:
for
et
in
entry_types
:
sum
=
sum
+
self
.
tree
.
xpath
(
'count(//'
+
et
+
')'
)
sum
=
sum
+
self
.
tree
.
xpath
(
'count(//'
+
et
+
')'
)
return
int
(
sum
)
return
int
(
sum
)
def
get_score
(
self
):
def
get_score
(
self
):
correct
=
0
correct
=
0
for
key
in
self
.
correct_map
:
for
key
in
self
.
correct_map
:
if
self
.
correct_map
[
key
]
==
u'correct'
:
if
self
.
correct_map
[
key
]
==
u'correct'
:
correct
+=
1
correct
+=
1
if
(
not
self
.
student_answers
)
or
len
(
self
.
student_answers
)
==
0
:
if
(
not
self
.
student_answers
)
or
len
(
self
.
student_answers
)
==
0
:
return
{
'score'
:
0
,
return
{
'score'
:
0
,
'total'
:
self
.
get_max_score
()}
'total'
:
self
.
get_max_score
()}
else
:
else
:
return
{
'score'
:
correct
,
return
{
'score'
:
correct
,
'total'
:
self
.
get_max_score
()}
'total'
:
self
.
get_max_score
()}
def
grade_answers
(
self
,
answers
):
def
grade_answers
(
self
,
answers
):
'''
'''
...
@@ -168,38 +168,36 @@ class LoncapaProblem(object):
...
@@ -168,38 +168,36 @@ class LoncapaProblem(object):
Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123
Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123
'''
'''
self
.
student_answers
=
answers
self
.
student_answers
=
answers
context
=
self
.
extract_context
(
self
.
tree
)
self
.
correct_map
=
dict
()
self
.
correct_map
=
dict
()
problems_simple
=
self
.
extract_problems
(
self
.
tree
)
problems_simple
=
self
.
extract_problems
(
self
.
tree
)
for
response
in
problems_simple
:
for
response
in
problems_simple
:
grader
=
response_types
[
response
.
tag
](
response
,
self
.
context
,
self
.
system
)
grader
=
response_types
[
response
.
tag
](
response
,
self
.
context
,
self
.
system
)
results
=
grader
.
get_score
(
answers
)
# call the responsetype instance to do the actual grading
results
=
grader
.
get_score
(
answers
)
# call the responsetype instance to do the actual grading
self
.
correct_map
.
update
(
results
)
self
.
correct_map
.
update
(
results
)
return
self
.
correct_map
return
self
.
correct_map
def
get_question_answers
(
self
):
def
get_question_answers
(
self
):
"""Returns a dict of answer_ids to answer values. If we can't generate
"""Returns a dict of answer_ids to answer values. If we can't generate
an answer (this sometimes happens in customresponses), that answer_id is
an answer (this sometimes happens in customresponses), that answer_id is
not included. Called by "show answers" button JSON request
not included. Called by "show answers" button JSON request
(see capa_module)
(see capa_module)
"""
"""
context
=
self
.
extract_context
(
self
.
tree
)
answer_map
=
dict
()
answer_map
=
dict
()
problems_simple
=
self
.
extract_problems
(
self
.
tree
)
# purified (flat) XML tree of just response queries
problems_simple
=
self
.
extract_problems
(
self
.
tree
)
# purified (flat) XML tree of just response queries
for
response
in
problems_simple
:
for
response
in
problems_simple
:
responder
=
response_types
[
response
.
tag
](
response
,
self
.
context
,
self
.
system
)
# instance of numericalresponse, customresponse,...
responder
=
response_types
[
response
.
tag
](
response
,
self
.
context
,
self
.
system
)
# instance of numericalresponse, customresponse,...
results
=
responder
.
get_answers
()
results
=
responder
.
get_answers
()
answer_map
.
update
(
results
)
# dict of (id,correct_answer)
answer_map
.
update
(
results
)
# dict of (id,correct_answer)
# example for the following: <textline size="5" correct_answer="saturated" />
# example for the following: <textline size="5" correct_answer="saturated" />
for
entry
in
problems_simple
.
xpath
(
"//"
+
"|//"
.
join
(
response_properties
+
entry_types
)):
for
entry
in
problems_simple
.
xpath
(
"//"
+
"|//"
.
join
(
response_properties
+
entry_types
)):
answer
=
entry
.
get
(
'correct_answer'
)
# correct answer, when specified elsewhere, eg in a textline
answer
=
entry
.
get
(
'correct_answer'
)
# correct answer, when specified elsewhere, eg in a textline
if
answer
:
if
answer
:
answer_map
[
entry
.
get
(
'id'
)]
=
contextualize_text
(
answer
,
self
.
context
)
answer_map
[
entry
.
get
(
'id'
)]
=
contextualize_text
(
answer
,
self
.
context
)
# include solutions from <solution>...</solution> stanzas
# include solutions from <solution>...</solution> stanzas
# Tentative merge; we should figure out how we want to handle hints and solutions
# Tentative merge; we should figure out how we want to handle hints and solutions
for
entry
in
self
.
tree
.
xpath
(
"//"
+
"|//"
.
join
(
solution_types
)):
for
entry
in
self
.
tree
.
xpath
(
"//"
+
"|//"
.
join
(
solution_types
)):
answer
=
etree
.
tostring
(
entry
)
answer
=
etree
.
tostring
(
entry
)
if
answer
:
if
answer
:
answer_map
[
entry
.
get
(
'id'
)]
=
answer
answer_map
[
entry
.
get
(
'id'
)]
=
answer
...
@@ -207,11 +205,10 @@ class LoncapaProblem(object):
...
@@ -207,11 +205,10 @@ class LoncapaProblem(object):
return
answer_map
return
answer_map
def
get_answer_ids
(
self
):
def
get_answer_ids
(
self
):
"""Return the IDs of all the responses -- these are the keys used for
"""Return the IDs of all the responses -- these are the keys used for
the dicts returned by grade_answers and get_question_answers. (Though
the dicts returned by grade_answers and get_question_answers. (Though
get_question_answers may only return a subset of these."""
get_question_answers may only return a subset of these."""
answer_ids
=
[]
answer_ids
=
[]
context
=
self
.
extract_context
(
self
.
tree
)
problems_simple
=
self
.
extract_problems
(
self
.
tree
)
problems_simple
=
self
.
extract_problems
(
self
.
tree
)
for
response
in
problems_simple
:
for
response
in
problems_simple
:
responder
=
response_types
[
response
.
tag
](
response
,
self
.
context
)
responder
=
response_types
[
response
.
tag
](
response
,
self
.
context
)
...
@@ -223,35 +220,35 @@ class LoncapaProblem(object):
...
@@ -223,35 +220,35 @@ class LoncapaProblem(object):
return
answer_ids
return
answer_ids
# ======= Private ========
# ======= Private ========
def
extract_context
(
self
,
tree
,
seed
=
struct
.
unpack
(
'i'
,
os
.
urandom
(
4
))[
0
]):
# private
def
extract_context
(
self
,
tree
,
seed
=
struct
.
unpack
(
'i'
,
os
.
urandom
(
4
))[
0
]):
# private
'''
'''
Extract content of <script>...</script> from the problem.xml file, and exec it in the
Extract content of <script>...</script> from the problem.xml file, and exec it in the
context of this problem. Provides ability to randomize problems, and also set
context of this problem. Provides ability to randomize problems, and also set
variables for problem answer checking.
variables for problem answer checking.
Problem XML goes to Python execution context. Runs everything in script tags
Problem XML goes to Python execution context. Runs everything in script tags
'''
'''
random
.
seed
(
self
.
seed
)
random
.
seed
(
self
.
seed
)
context
=
{
'global_context'
:
global_context
}
# save global context in here also
context
=
{
'global_context'
:
global_context
}
# save global context in here also
context
.
update
(
global_context
)
# initialize context to have stuff in global_context
context
.
update
(
global_context
)
# initialize context to have stuff in global_context
context
[
'__builtins__'
]
=
globals
()[
'__builtins__'
]
# put globals there also
context
[
'__builtins__'
]
=
globals
()[
'__builtins__'
]
# put globals there also
context
[
'the_lcp'
]
=
self
# pass instance of LoncapaProblem in
context
[
'the_lcp'
]
=
self
# pass instance of LoncapaProblem in
#for script in tree.xpath('/problem/script'):
#for script in tree.xpath('/problem/script'):
for
script
in
tree
.
findall
(
'.//script'
):
for
script
in
tree
.
findall
(
'.//script'
):
stype
=
script
.
get
(
'type'
)
stype
=
script
.
get
(
'type'
)
if
stype
:
if
stype
:
if
'javascript'
in
stype
:
continue
# skip javascript
if
'javascript'
in
stype
:
if
'perl'
in
stype
:
continue
# skip perl
continue
# skip javascript
# TODO: evaluate only python
if
'perl'
in
stype
:
continue
# skip perl
# TODO: evaluate only python
code
=
script
.
text
code
=
script
.
text
XMLESC
=
{
"'"
:
"'"
,
"""
:
'"'
}
XMLESC
=
{
"'"
:
"'"
,
"""
:
'"'
}
code
=
unescape
(
code
,
XMLESC
)
code
=
unescape
(
code
,
XMLESC
)
try
:
try
:
exec
code
in
context
,
context
# use "context" for global context; thus defs in code are global within code
exec
code
in
context
,
context
# use "context" for global context; thus defs in code are global within code
except
Exception
:
except
Exception
:
log
.
exception
(
"Error while execing code: "
+
code
)
log
.
exception
(
"Error while execing code: "
+
code
)
return
context
return
context
...
@@ -265,11 +262,11 @@ class LoncapaProblem(object):
...
@@ -265,11 +262,11 @@ class LoncapaProblem(object):
if
problemtree
.
tag
in
html_problem_semantics
:
if
problemtree
.
tag
in
html_problem_semantics
:
return
return
problemid
=
problemtree
.
get
(
'id'
)
# my ID
problemid
=
problemtree
.
get
(
'id'
)
# my ID
# used to be
# used to be
# if problemtree.tag in html_special_response:
# if problemtree.tag in html_special_response:
if
problemtree
.
tag
in
inputtypes
.
get_input_xml_tags
():
if
problemtree
.
tag
in
inputtypes
.
get_input_xml_tags
():
# status is currently the answer for the problem ID for the input element,
# status is currently the answer for the problem ID for the input element,
# but it will turn into a dict containing both the answer and any associated message
# but it will turn into a dict containing both the answer and any associated message
...
@@ -283,7 +280,7 @@ class LoncapaProblem(object):
...
@@ -283,7 +280,7 @@ class LoncapaProblem(object):
value
=
self
.
student_answers
[
problemid
]
value
=
self
.
student_answers
[
problemid
]
#### This code is a hack. It was merged to help bring two branches
#### This code is a hack. It was merged to help bring two branches
#### in sync, but should be replaced. msg should be passed in a
#### in sync, but should be replaced. msg should be passed in a
#### response_type
#### response_type
# prepare the response message, if it exists in correct_map
# prepare the response message, if it exists in correct_map
if
'msg'
in
self
.
correct_map
:
if
'msg'
in
self
.
correct_map
:
...
@@ -296,112 +293,111 @@ class LoncapaProblem(object):
...
@@ -296,112 +293,111 @@ class LoncapaProblem(object):
# do the rendering
# do the rendering
# This should be broken out into a helper function
# This should be broken out into a helper function
# that handles all input objects
# that handles all input objects
render_object
=
inputtypes
.
SimpleInput
(
system
=
self
.
system
,
render_object
=
inputtypes
.
SimpleInput
(
system
=
self
.
system
,
xml
=
problemtree
,
xml
=
problemtree
,
state
=
{
'value'
:
value
,
state
=
{
'value'
:
value
,
'status'
:
status
,
'status'
:
status
,
'id'
:
problemtree
.
get
(
'id'
),
'id'
:
problemtree
.
get
(
'id'
),
'feedback'
:{
'message'
:
msg
}
'feedback'
:
{
'message'
:
msg
}
},
},
use
=
'capa_input'
)
use
=
'capa_input'
)
return
render_object
.
get_html
()
#
function(problemtree, value, status, msg) # render the special response (textline, schematic,...)
return
render_object
.
get_html
()
#
function(problemtree, value, status, msg) # render the special response (textline, schematic,...)
tree
=
Element
(
problemtree
.
tag
)
tree
=
Element
(
problemtree
.
tag
)
for
item
in
problemtree
:
for
item
in
problemtree
:
subitems
=
self
.
extract_html
(
item
)
subitems
=
self
.
extract_html
(
item
)
if
subitems
is
not
None
:
if
subitems
is
not
None
:
for
subitem
in
subitems
:
for
subitem
in
subitems
:
tree
.
append
(
subitem
)
tree
.
append
(
subitem
)
for
(
key
,
value
)
in
problemtree
.
items
():
for
(
key
,
value
)
in
problemtree
.
items
():
tree
.
set
(
key
,
value
)
tree
.
set
(
key
,
value
)
tree
.
text
=
problemtree
.
text
tree
.
text
=
problemtree
.
text
tree
.
tail
=
problemtree
.
tail
tree
.
tail
=
problemtree
.
tail
if
problemtree
.
tag
in
html_transforms
:
if
problemtree
.
tag
in
html_transforms
:
tree
.
tag
=
html_transforms
[
problemtree
.
tag
][
'tag'
]
tree
.
tag
=
html_transforms
[
problemtree
.
tag
][
'tag'
]
# Reset attributes. Otherwise, we get metadata in HTML
# Reset attributes. Otherwise, we get metadata in HTML
# (e.g. answers)
# (e.g. answers)
# TODO: We should remove and not zero them.
# TODO: We should remove and not zero them.
# I'm not sure how to do that quickly with lxml
# I'm not sure how to do that quickly with lxml
for
k
in
tree
.
keys
():
for
k
in
tree
.
keys
():
tree
.
set
(
k
,
""
)
tree
.
set
(
k
,
""
)
# TODO: Fix. This loses Element().tail
# TODO: Fix. This loses Element().tail
#if problemtree.tag in html_skip:
#if problemtree.tag in html_skip:
# return tree
# return tree
return
[
tree
]
return
[
tree
]
def
preprocess_problem
(
self
,
tree
,
correct_map
=
dict
(),
answer_map
=
dict
()):
# private
def
preprocess_problem
(
self
,
tree
,
correct_map
=
dict
(),
answer_map
=
dict
()):
# private
'''
'''
Assign IDs to all the responses
Assign IDs to all the responses
Assign sub-IDs to all entries (textline, schematic, etc.)
Assign sub-IDs to all entries (textline, schematic, etc.)
Annoted correctness and value
Annoted correctness and value
In-place transformation
In-place transformation
'''
'''
response_id
=
1
response_id
=
1
for
response
in
tree
.
xpath
(
'//'
+
"|//"
.
join
(
response_types
)):
for
response
in
tree
.
xpath
(
'//'
+
"|//"
.
join
(
response_types
)):
response_id_str
=
self
.
problem_id
+
"_"
+
str
(
response_id
)
response_id_str
=
self
.
problem_id
+
"_"
+
str
(
response_id
)
response
.
attrib
[
'id'
]
=
response_id_str
response
.
attrib
[
'id'
]
=
response_id_str
if
response_id
not
in
correct_map
:
if
response_id
not
in
correct_map
:
correct
=
'unsubmitted'
correct
=
'unsubmitted'
response
.
attrib
[
'state'
]
=
correct
response
.
attrib
[
'state'
]
=
correct
response_id
=
response_id
+
1
response_id
=
response_id
+
1
answer_id
=
1
answer_id
=
1
for
entry
in
tree
.
xpath
(
"|"
.
join
([
'//'
+
response
.
tag
+
'[@id=$id]//'
+
x
for
x
in
(
entry_types
+
solution_types
)]),
for
entry
in
tree
.
xpath
(
"|"
.
join
([
'//'
+
response
.
tag
+
'[@id=$id]//'
+
x
for
x
in
(
entry_types
+
solution_types
)]),
id
=
response_id_str
):
id
=
response_id_str
):
# assign one answer_id for each entry_type or solution_type
# assign one answer_id for each entry_type or solution_type
entry
.
attrib
[
'response_id'
]
=
str
(
response_id
)
entry
.
attrib
[
'response_id'
]
=
str
(
response_id
)
entry
.
attrib
[
'answer_id'
]
=
str
(
answer_id
)
entry
.
attrib
[
'answer_id'
]
=
str
(
answer_id
)
entry
.
attrib
[
'id'
]
=
"
%
s_
%
i_
%
i"
%
(
self
.
problem_id
,
response_id
,
answer_id
)
entry
.
attrib
[
'id'
]
=
"
%
s_
%
i_
%
i"
%
(
self
.
problem_id
,
response_id
,
answer_id
)
answer_id
=
answer_id
+
1
answer_id
=
answer_id
+
1
# <solution>...</solution> may not be associated with any specific response; give IDs for those separately
# <solution>...</solution> may not be associated with any specific response; give IDs for those separately
# TODO: We should make the namespaces consistent and unique (e.g. %s_problem_%i).
# TODO: We should make the namespaces consistent and unique (e.g. %s_problem_%i).
solution_id
=
1
solution_id
=
1
for
solution
in
tree
.
findall
(
'.//solution'
):
for
solution
in
tree
.
findall
(
'.//solution'
):
solution
.
attrib
[
'id'
]
=
"
%
s_solution_
%
i"
%
(
self
.
problem_id
,
solution_id
)
solution
.
attrib
[
'id'
]
=
"
%
s_solution_
%
i"
%
(
self
.
problem_id
,
solution_id
)
solution_id
+=
1
solution_id
+=
1
def
extract_problems
(
self
,
problem_tree
):
def
extract_problems
(
self
,
problem_tree
):
''' Remove layout from the problem, and give a purified XML tree of just the problems '''
''' Remove layout from the problem, and give a purified XML tree of just the problems '''
problem_tree
=
copy
.
deepcopy
(
problem_tree
)
problem_tree
=
copy
.
deepcopy
(
problem_tree
)
tree
=
Element
(
'problem'
)
tree
=
Element
(
'problem'
)
for
response
in
problem_tree
.
xpath
(
"//"
+
"|//"
.
join
(
response_types
)):
for
response
in
problem_tree
.
xpath
(
"//"
+
"|//"
.
join
(
response_types
)):
newresponse
=
copy
.
copy
(
response
)
newresponse
=
copy
.
copy
(
response
)
for
e
in
newresponse
:
for
e
in
newresponse
:
newresponse
.
remove
(
e
)
newresponse
.
remove
(
e
)
# copy.copy is needed to make xpath work right. Otherwise, it starts at the root
# copy.copy is needed to make xpath work right. Otherwise, it starts at the root
# of the tree. We should figure out if there's some work-around
# of the tree. We should figure out if there's some work-around
for
e
in
copy
.
copy
(
response
)
.
xpath
(
"//"
+
"|//"
.
join
(
response_properties
+
entry_types
)):
for
e
in
copy
.
copy
(
response
)
.
xpath
(
"//"
+
"|//"
.
join
(
response_properties
+
entry_types
)):
newresponse
.
append
(
e
)
newresponse
.
append
(
e
)
tree
.
append
(
newresponse
)
tree
.
append
(
newresponse
)
return
tree
return
tree
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
problem_id
=
'simpleFormula'
problem_id
=
'simpleFormula'
filename
=
'simpleFormula.xml'
filename
=
'simpleFormula.xml'
problem_id
=
'resistor'
problem_id
=
'resistor'
filename
=
'resistor.xml'
filename
=
'resistor.xml'
lcp
=
LoncapaProblem
(
filename
,
problem_id
)
lcp
=
LoncapaProblem
(
filename
,
problem_id
)
context
=
lcp
.
extract_context
(
lcp
.
tree
)
context
=
lcp
.
extract_context
(
lcp
.
tree
)
problem
=
lcp
.
extract_problems
(
lcp
.
tree
)
problem
=
lcp
.
extract_problems
(
lcp
.
tree
)
print
lcp
.
grade_problems
({
'resistor_2_1'
:
'1.0'
,
'resistor_3_1'
:
'2.0'
})
print
lcp
.
grade_problems
({
'resistor_2_1'
:
'1.0'
,
'resistor_3_1'
:
'2.0'
})
#print lcp.grade_problems({'simpleFormula_2_1':'3*x^3'})
#print lcp.grade_problems({'simpleFormula_2_1':'3*x^3'})
#numericalresponse(problem, context)
#numericalresponse(problem, context)
#print etree.tostring((lcp.tree))
#print etree.tostring((lcp.tree))
print
'============'
print
'============'
print
print
#print etree.tostring(lcp.extract_problems(lcp.tree))
#print etree.tostring(lcp.extract_problems(lcp.tree))
print
lcp
.
get_html
()
print
lcp
.
get_html
()
#print extract_context(tree)
#print extract_context(tree)
# def handle_fr(self, element):
# def handle_fr(self, element):
...
@@ -411,4 +407,4 @@ if __name__=='__main__':
...
@@ -411,4 +407,4 @@ if __name__=='__main__':
# "sample_range":dict(zip(variables, sranges)),
# "sample_range":dict(zip(variables, sranges)),
# "samples_count": numsamples,
# "samples_count": numsamples,
# "id":id,
# "id":id,
# self.questions[self.lid]=problem
# self.questions[self.lid]=problem
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